From e45890a6165e4a7551ec1c7d4844ee1347be4047 Mon Sep 17 00:00:00 2001 From: Lars Hamann Date: Mon, 19 Oct 1998 22:46:38 +0000 Subject: [PATCH] rearranged some functions (gtk_clist_set_column_auto_resize): new Mon Oct 19 23:44:41 1998 Lars Hamann * gtk/gtkclist.c: rearranged some functions (gtk_clist_set_column_auto_resize): new function. toggle auto_resize flag of column (gtk_clist_set_column_resizeable): if resizeable disable auto_resize (gtk_clist_set_border): deprecated function, use gtk_clist_set_shadow_type instead. (gtk_clist_set_shadow_type): replacement for gtk_clist_set_border (adjust_scrollbars): some cleanups (select_row) (unselect_row): removed. replaced by equivalent gtk_signal_emit calls (add_style_data): removed, use gtk_clist_style_set instead (gtk_clist_style_set): fill in size data, after style was set. (set_cell_contents) (gtk_clist_set_shift) (gtk_clist_set_row_style) (gtk_clist_set_cell_style): auto_resize columns if needed (column_auto_resize): resize column if needed for auto_resize (real_clear): disable auto_resize while list destroy (resize_column): removed * gtk/gtkctree.c : (gtk_ctree_remove_node) (gtk_ctree_set_line_style) (gtk_ctree_set_expander_style) (gtk_ctree_node_set_row_style) (gtk_ctree_node_set_cell_style) (set_cell_contents) (gtk_ctree_node_set_shift) (gtk_ctree_set_spacing) (real_tree_move) (gtk_ctree_set_indent) (gtk_ctree_insert_node) (real_tree_collapse) (real_tree_expand) (column_auto_resize): auto_resize columns if needed (gtk_ctree_collapse_recursive) (gtk_ctree_collapse_to_depth) (real_clear): disable auto_resize while processing the tree * gtk/testgtk.c (create_clist) (create_ctree): set auto_resize for one column --- ChangeLog | 33 + ChangeLog.pre-2-0 | 33 + ChangeLog.pre-2-10 | 33 + ChangeLog.pre-2-2 | 33 + ChangeLog.pre-2-4 | 33 + ChangeLog.pre-2-6 | 33 + ChangeLog.pre-2-8 | 33 + gtk/gtkclist.c | 9060 +++++++++++++++++++++++--------------------- gtk/gtkclist.h | 180 +- gtk/gtkctree.c | 514 ++- gtk/testgtk.c | 32 +- tests/testgtk.c | 32 +- 12 files changed, 5517 insertions(+), 4532 deletions(-) diff --git a/ChangeLog b/ChangeLog index 80344ff2a3..dee018fe53 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,36 @@ +Mon Oct 19 23:44:41 1998 Lars Hamann + + * gtk/gtkclist.c: rearranged some functions + (gtk_clist_set_column_auto_resize): new function. toggle auto_resize + flag of column + (gtk_clist_set_column_resizeable): if resizeable disable auto_resize + (gtk_clist_set_border): deprecated function, use + gtk_clist_set_shadow_type instead. + (gtk_clist_set_shadow_type): replacement for gtk_clist_set_border + (adjust_scrollbars): some cleanups + (select_row) (unselect_row): removed. replaced by equivalent + gtk_signal_emit calls + (add_style_data): removed, use gtk_clist_style_set instead + (gtk_clist_style_set): fill in size data, after style was set. + (set_cell_contents) (gtk_clist_set_shift) (gtk_clist_set_row_style) + (gtk_clist_set_cell_style): auto_resize columns if needed + (column_auto_resize): resize column if needed for auto_resize + (real_clear): disable auto_resize while list destroy + (resize_column): removed + + * gtk/gtkctree.c : (gtk_ctree_remove_node) + (gtk_ctree_set_line_style) (gtk_ctree_set_expander_style) + (gtk_ctree_node_set_row_style) (gtk_ctree_node_set_cell_style) + (set_cell_contents) (gtk_ctree_node_set_shift) (gtk_ctree_set_spacing) + (real_tree_move) (gtk_ctree_set_indent) (gtk_ctree_insert_node) + (real_tree_collapse) (real_tree_expand) (column_auto_resize): + auto_resize columns if needed + (gtk_ctree_collapse_recursive) (gtk_ctree_collapse_to_depth) + (real_clear): disable auto_resize while processing the tree + + * gtk/testgtk.c (create_clist) (create_ctree): set auto_resize + for one column + Mon Oct 19 08:31:36 1998 Owen Taylor * gtk/gtkdnd.c (gtk_drag_selection_received): Fixed diff --git a/ChangeLog.pre-2-0 b/ChangeLog.pre-2-0 index 80344ff2a3..dee018fe53 100644 --- a/ChangeLog.pre-2-0 +++ b/ChangeLog.pre-2-0 @@ -1,3 +1,36 @@ +Mon Oct 19 23:44:41 1998 Lars Hamann + + * gtk/gtkclist.c: rearranged some functions + (gtk_clist_set_column_auto_resize): new function. toggle auto_resize + flag of column + (gtk_clist_set_column_resizeable): if resizeable disable auto_resize + (gtk_clist_set_border): deprecated function, use + gtk_clist_set_shadow_type instead. + (gtk_clist_set_shadow_type): replacement for gtk_clist_set_border + (adjust_scrollbars): some cleanups + (select_row) (unselect_row): removed. replaced by equivalent + gtk_signal_emit calls + (add_style_data): removed, use gtk_clist_style_set instead + (gtk_clist_style_set): fill in size data, after style was set. + (set_cell_contents) (gtk_clist_set_shift) (gtk_clist_set_row_style) + (gtk_clist_set_cell_style): auto_resize columns if needed + (column_auto_resize): resize column if needed for auto_resize + (real_clear): disable auto_resize while list destroy + (resize_column): removed + + * gtk/gtkctree.c : (gtk_ctree_remove_node) + (gtk_ctree_set_line_style) (gtk_ctree_set_expander_style) + (gtk_ctree_node_set_row_style) (gtk_ctree_node_set_cell_style) + (set_cell_contents) (gtk_ctree_node_set_shift) (gtk_ctree_set_spacing) + (real_tree_move) (gtk_ctree_set_indent) (gtk_ctree_insert_node) + (real_tree_collapse) (real_tree_expand) (column_auto_resize): + auto_resize columns if needed + (gtk_ctree_collapse_recursive) (gtk_ctree_collapse_to_depth) + (real_clear): disable auto_resize while processing the tree + + * gtk/testgtk.c (create_clist) (create_ctree): set auto_resize + for one column + Mon Oct 19 08:31:36 1998 Owen Taylor * gtk/gtkdnd.c (gtk_drag_selection_received): Fixed diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 80344ff2a3..dee018fe53 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,36 @@ +Mon Oct 19 23:44:41 1998 Lars Hamann + + * gtk/gtkclist.c: rearranged some functions + (gtk_clist_set_column_auto_resize): new function. toggle auto_resize + flag of column + (gtk_clist_set_column_resizeable): if resizeable disable auto_resize + (gtk_clist_set_border): deprecated function, use + gtk_clist_set_shadow_type instead. + (gtk_clist_set_shadow_type): replacement for gtk_clist_set_border + (adjust_scrollbars): some cleanups + (select_row) (unselect_row): removed. replaced by equivalent + gtk_signal_emit calls + (add_style_data): removed, use gtk_clist_style_set instead + (gtk_clist_style_set): fill in size data, after style was set. + (set_cell_contents) (gtk_clist_set_shift) (gtk_clist_set_row_style) + (gtk_clist_set_cell_style): auto_resize columns if needed + (column_auto_resize): resize column if needed for auto_resize + (real_clear): disable auto_resize while list destroy + (resize_column): removed + + * gtk/gtkctree.c : (gtk_ctree_remove_node) + (gtk_ctree_set_line_style) (gtk_ctree_set_expander_style) + (gtk_ctree_node_set_row_style) (gtk_ctree_node_set_cell_style) + (set_cell_contents) (gtk_ctree_node_set_shift) (gtk_ctree_set_spacing) + (real_tree_move) (gtk_ctree_set_indent) (gtk_ctree_insert_node) + (real_tree_collapse) (real_tree_expand) (column_auto_resize): + auto_resize columns if needed + (gtk_ctree_collapse_recursive) (gtk_ctree_collapse_to_depth) + (real_clear): disable auto_resize while processing the tree + + * gtk/testgtk.c (create_clist) (create_ctree): set auto_resize + for one column + Mon Oct 19 08:31:36 1998 Owen Taylor * gtk/gtkdnd.c (gtk_drag_selection_received): Fixed diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2 index 80344ff2a3..dee018fe53 100644 --- a/ChangeLog.pre-2-2 +++ b/ChangeLog.pre-2-2 @@ -1,3 +1,36 @@ +Mon Oct 19 23:44:41 1998 Lars Hamann + + * gtk/gtkclist.c: rearranged some functions + (gtk_clist_set_column_auto_resize): new function. toggle auto_resize + flag of column + (gtk_clist_set_column_resizeable): if resizeable disable auto_resize + (gtk_clist_set_border): deprecated function, use + gtk_clist_set_shadow_type instead. + (gtk_clist_set_shadow_type): replacement for gtk_clist_set_border + (adjust_scrollbars): some cleanups + (select_row) (unselect_row): removed. replaced by equivalent + gtk_signal_emit calls + (add_style_data): removed, use gtk_clist_style_set instead + (gtk_clist_style_set): fill in size data, after style was set. + (set_cell_contents) (gtk_clist_set_shift) (gtk_clist_set_row_style) + (gtk_clist_set_cell_style): auto_resize columns if needed + (column_auto_resize): resize column if needed for auto_resize + (real_clear): disable auto_resize while list destroy + (resize_column): removed + + * gtk/gtkctree.c : (gtk_ctree_remove_node) + (gtk_ctree_set_line_style) (gtk_ctree_set_expander_style) + (gtk_ctree_node_set_row_style) (gtk_ctree_node_set_cell_style) + (set_cell_contents) (gtk_ctree_node_set_shift) (gtk_ctree_set_spacing) + (real_tree_move) (gtk_ctree_set_indent) (gtk_ctree_insert_node) + (real_tree_collapse) (real_tree_expand) (column_auto_resize): + auto_resize columns if needed + (gtk_ctree_collapse_recursive) (gtk_ctree_collapse_to_depth) + (real_clear): disable auto_resize while processing the tree + + * gtk/testgtk.c (create_clist) (create_ctree): set auto_resize + for one column + Mon Oct 19 08:31:36 1998 Owen Taylor * gtk/gtkdnd.c (gtk_drag_selection_received): Fixed diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 index 80344ff2a3..dee018fe53 100644 --- a/ChangeLog.pre-2-4 +++ b/ChangeLog.pre-2-4 @@ -1,3 +1,36 @@ +Mon Oct 19 23:44:41 1998 Lars Hamann + + * gtk/gtkclist.c: rearranged some functions + (gtk_clist_set_column_auto_resize): new function. toggle auto_resize + flag of column + (gtk_clist_set_column_resizeable): if resizeable disable auto_resize + (gtk_clist_set_border): deprecated function, use + gtk_clist_set_shadow_type instead. + (gtk_clist_set_shadow_type): replacement for gtk_clist_set_border + (adjust_scrollbars): some cleanups + (select_row) (unselect_row): removed. replaced by equivalent + gtk_signal_emit calls + (add_style_data): removed, use gtk_clist_style_set instead + (gtk_clist_style_set): fill in size data, after style was set. + (set_cell_contents) (gtk_clist_set_shift) (gtk_clist_set_row_style) + (gtk_clist_set_cell_style): auto_resize columns if needed + (column_auto_resize): resize column if needed for auto_resize + (real_clear): disable auto_resize while list destroy + (resize_column): removed + + * gtk/gtkctree.c : (gtk_ctree_remove_node) + (gtk_ctree_set_line_style) (gtk_ctree_set_expander_style) + (gtk_ctree_node_set_row_style) (gtk_ctree_node_set_cell_style) + (set_cell_contents) (gtk_ctree_node_set_shift) (gtk_ctree_set_spacing) + (real_tree_move) (gtk_ctree_set_indent) (gtk_ctree_insert_node) + (real_tree_collapse) (real_tree_expand) (column_auto_resize): + auto_resize columns if needed + (gtk_ctree_collapse_recursive) (gtk_ctree_collapse_to_depth) + (real_clear): disable auto_resize while processing the tree + + * gtk/testgtk.c (create_clist) (create_ctree): set auto_resize + for one column + Mon Oct 19 08:31:36 1998 Owen Taylor * gtk/gtkdnd.c (gtk_drag_selection_received): Fixed diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index 80344ff2a3..dee018fe53 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,3 +1,36 @@ +Mon Oct 19 23:44:41 1998 Lars Hamann + + * gtk/gtkclist.c: rearranged some functions + (gtk_clist_set_column_auto_resize): new function. toggle auto_resize + flag of column + (gtk_clist_set_column_resizeable): if resizeable disable auto_resize + (gtk_clist_set_border): deprecated function, use + gtk_clist_set_shadow_type instead. + (gtk_clist_set_shadow_type): replacement for gtk_clist_set_border + (adjust_scrollbars): some cleanups + (select_row) (unselect_row): removed. replaced by equivalent + gtk_signal_emit calls + (add_style_data): removed, use gtk_clist_style_set instead + (gtk_clist_style_set): fill in size data, after style was set. + (set_cell_contents) (gtk_clist_set_shift) (gtk_clist_set_row_style) + (gtk_clist_set_cell_style): auto_resize columns if needed + (column_auto_resize): resize column if needed for auto_resize + (real_clear): disable auto_resize while list destroy + (resize_column): removed + + * gtk/gtkctree.c : (gtk_ctree_remove_node) + (gtk_ctree_set_line_style) (gtk_ctree_set_expander_style) + (gtk_ctree_node_set_row_style) (gtk_ctree_node_set_cell_style) + (set_cell_contents) (gtk_ctree_node_set_shift) (gtk_ctree_set_spacing) + (real_tree_move) (gtk_ctree_set_indent) (gtk_ctree_insert_node) + (real_tree_collapse) (real_tree_expand) (column_auto_resize): + auto_resize columns if needed + (gtk_ctree_collapse_recursive) (gtk_ctree_collapse_to_depth) + (real_clear): disable auto_resize while processing the tree + + * gtk/testgtk.c (create_clist) (create_ctree): set auto_resize + for one column + Mon Oct 19 08:31:36 1998 Owen Taylor * gtk/gtkdnd.c (gtk_drag_selection_received): Fixed diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index 80344ff2a3..dee018fe53 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,36 @@ +Mon Oct 19 23:44:41 1998 Lars Hamann + + * gtk/gtkclist.c: rearranged some functions + (gtk_clist_set_column_auto_resize): new function. toggle auto_resize + flag of column + (gtk_clist_set_column_resizeable): if resizeable disable auto_resize + (gtk_clist_set_border): deprecated function, use + gtk_clist_set_shadow_type instead. + (gtk_clist_set_shadow_type): replacement for gtk_clist_set_border + (adjust_scrollbars): some cleanups + (select_row) (unselect_row): removed. replaced by equivalent + gtk_signal_emit calls + (add_style_data): removed, use gtk_clist_style_set instead + (gtk_clist_style_set): fill in size data, after style was set. + (set_cell_contents) (gtk_clist_set_shift) (gtk_clist_set_row_style) + (gtk_clist_set_cell_style): auto_resize columns if needed + (column_auto_resize): resize column if needed for auto_resize + (real_clear): disable auto_resize while list destroy + (resize_column): removed + + * gtk/gtkctree.c : (gtk_ctree_remove_node) + (gtk_ctree_set_line_style) (gtk_ctree_set_expander_style) + (gtk_ctree_node_set_row_style) (gtk_ctree_node_set_cell_style) + (set_cell_contents) (gtk_ctree_node_set_shift) (gtk_ctree_set_spacing) + (real_tree_move) (gtk_ctree_set_indent) (gtk_ctree_insert_node) + (real_tree_collapse) (real_tree_expand) (column_auto_resize): + auto_resize columns if needed + (gtk_ctree_collapse_recursive) (gtk_ctree_collapse_to_depth) + (real_clear): disable auto_resize while processing the tree + + * gtk/testgtk.c (create_clist) (create_ctree): set auto_resize + for one column + Mon Oct 19 08:31:36 1998 Owen Taylor * gtk/gtkdnd.c (gtk_drag_selection_received): Fixed diff --git a/gtk/gtkclist.c b/gtk/gtkclist.c index 886174ed8a..6e048f4ad6 100644 --- a/gtk/gtkclist.c +++ b/gtk/gtkclist.c @@ -143,254 +143,222 @@ enum SYNC_INSERT }; - -typedef void (*GtkCListSignal1) (GtkObject * object, - gint arg1, - gint arg2, - GdkEvent * arg3, - gpointer data); - -typedef void (*GtkCListSignal2) (GtkObject *object, - gpointer data); - -typedef void (*GtkCListSignal3) (GtkObject * object, - gint arg1, - gpointer data); -typedef void (*GtkCListSignal4) (GtkObject * object, - gint arg1, - gfloat arg2, - gpointer data); -typedef void (*GtkCListSignal5) (GtkObject * object, - gint arg1, - gfloat arg2, - gboolean arg3, - gpointer data); - - static void sync_selection (GtkCList * clist, gint row, gint mode); /* GtkCList Methods */ -static void gtk_clist_class_init (GtkCListClass * klass); -static void gtk_clist_init (GtkCList * clist); -static void real_clear (GtkCList * clist); +static void gtk_clist_class_init (GtkCListClass *klass); +static void gtk_clist_init (GtkCList *clist); /* GtkObject Methods */ -static void gtk_clist_destroy (GtkObject * object); -static void gtk_clist_finalize (GtkObject * object); - +static void gtk_clist_destroy (GtkObject *object); +static void gtk_clist_finalize (GtkObject *object); /* GtkWidget Methods */ -static void gtk_clist_realize (GtkWidget * widget); -static void gtk_clist_unrealize (GtkWidget * widget); -static void gtk_clist_map (GtkWidget * widget); -static void gtk_clist_unmap (GtkWidget * widget); -static void gtk_clist_draw (GtkWidget * widget, - GdkRectangle * area); -static gint gtk_clist_expose (GtkWidget * widget, - GdkEventExpose * event); -static gint gtk_clist_button_press (GtkWidget * widget, - GdkEventButton * event); -static gint gtk_clist_button_release (GtkWidget * widget, - GdkEventButton * event); -static gint gtk_clist_motion (GtkWidget * widget, - GdkEventMotion * event); -static void gtk_clist_size_request (GtkWidget * widget, - GtkRequisition * requisition); -static void gtk_clist_size_allocate (GtkWidget * widget, - GtkAllocation * allocation); -static gint get_selection_info (GtkCList * clist, - gint x, - gint y, - gint * row, - gint * column); +static void gtk_clist_realize (GtkWidget *widget); +static void gtk_clist_unrealize (GtkWidget *widget); +static void gtk_clist_map (GtkWidget *widget); +static void gtk_clist_unmap (GtkWidget *widget); +static void gtk_clist_draw (GtkWidget *widget, + GdkRectangle *area); +static gint gtk_clist_expose (GtkWidget *widget, + GdkEventExpose *event); +static gint gtk_clist_key_press (GtkWidget *widget, + GdkEventKey *event); +static gint gtk_clist_button_press (GtkWidget *widget, + GdkEventButton *event); +static gint gtk_clist_button_release (GtkWidget *widget, + GdkEventButton *event); +static gint gtk_clist_motion (GtkWidget *widget, + GdkEventMotion *event); +static void gtk_clist_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_clist_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_clist_draw_focus (GtkWidget *widget); +static gint gtk_clist_focus_in (GtkWidget *widget, + GdkEventFocus *event); +static gint gtk_clist_focus_out (GtkWidget *widget, + GdkEventFocus *event); +static gint gtk_clist_focus (GtkContainer *container, + GtkDirectionType direction); +static void gtk_clist_style_set (GtkWidget *widget, + GtkStyle *previous_style); /* GtkContainer Methods */ -static void gtk_clist_forall (GtkContainer *container, - gboolean include_internals, - GtkCallback callback, - gpointer callback_data); - -/* Drawing */ -static void get_cell_style (GtkCList *clist, - GtkCListRow *clist_row, - gint state, - gint column, - GtkStyle **style, - GdkGC **fg_gc, - GdkGC **bg_gc); -static gint draw_cell_pixmap (GdkWindow *window, - GdkRectangle *clip_rectangle, - GdkGC *fg_gc, - GdkPixmap *pixmap, - GdkBitmap *mask, - gint x, - gint y, - gint width, - gint height); -static void draw_row (GtkCList * clist, - GdkRectangle * area, - gint row, - GtkCListRow * clist_row); -static void draw_rows (GtkCList * clist, - GdkRectangle * area); - -/* Size Allocation */ -static void size_allocate_title_buttons (GtkCList * clist); -static void size_allocate_columns (GtkCList * clist); +static void gtk_clist_set_focus_child (GtkContainer *container, + GtkWidget *child); +static void gtk_clist_forall (GtkContainer *container, + gboolean include_internals, + GtkCallback callback, + gpointer callback_data); /* Selection */ -static void toggle_row (GtkCList * clist, - gint row, - gint column, - GdkEvent * event); -static void select_row (GtkCList * clist, - gint row, - gint column, - GdkEvent * event); -static void unselect_row (GtkCList * clist, - gint row, - gint column, - GdkEvent * event); -static void real_select_row (GtkCList * clist, - gint row, - gint column, - GdkEvent * event); -static void real_unselect_row (GtkCList * clist, - gint row, - gint column, - GdkEvent * event); -static void update_extended_selection (GtkCList *clist, - gint row); -static GList * selection_find (GtkCList *clist, - gint row_number, - GList *row_list_element); -static void real_select_all (GtkCList * clist); -static void real_unselect_all (GtkCList * clist); -static void move_vertical (GtkCList *clist, - gint row, - gfloat align); -static void move_horizontal (GtkCList *clist, - gint diff); -static void real_undo_selection (GtkCList * clist); -static void fake_unselect_all (GtkCList *clist, - gint row); -static void fake_toggle_row (GtkCList *clist, - gint row); -static void resync_selection (GtkCList *clist, - GdkEvent *event); +static void toggle_row (GtkCList *clist, + gint row, + gint column, + GdkEvent *event); +static void real_select_row (GtkCList *clist, + gint row, + gint column, + GdkEvent *event); +static void real_unselect_row (GtkCList *clist, + gint row, + gint column, + GdkEvent *event); +static void update_extended_selection (GtkCList *clist, + gint row); +static GList *selection_find (GtkCList *clist, + gint row_number, + GList *row_list_element); +static void real_select_all (GtkCList *clist); +static void real_unselect_all (GtkCList *clist); +static void move_vertical (GtkCList *clist, + gint row, + gfloat align); +static void move_horizontal (GtkCList *clist, + gint diff); +static void real_undo_selection (GtkCList *clist); +static void fake_unselect_all (GtkCList *clist, + gint row); +static void fake_toggle_row (GtkCList *clist, + gint row); +static void resync_selection (GtkCList *clist, + GdkEvent *event); +static void sync_selection (GtkCList *clist, + gint row, + gint mode); +static void set_anchor (GtkCList *clist, + gboolean add_mode, + gint anchor, + gint undo_anchor); +static void start_selection (GtkCList *clist); +static void end_selection (GtkCList *clist); +static void toggle_add_mode (GtkCList *clist); +static void toggle_focus_row (GtkCList *clist); +static void move_focus_row (GtkCList *clist, + GtkScrollType scroll_type, + gfloat position); +static void scroll_horizontal (GtkCList *clist, + GtkScrollType scroll_type, + gfloat position); +static void scroll_vertical (GtkCList *clist, + GtkScrollType scroll_type, + gfloat position); +static void extend_selection (GtkCList *clist, + GtkScrollType scroll_type, + gfloat position, + gboolean auto_start_selection); +static gint get_selection_info (GtkCList *clist, + gint x, + gint y, + gint *row, + gint *column); /* Resize Columns */ -static void draw_xor_line (GtkCList * clist); -static gint new_column_width (GtkCList * clist, - gint column, - gint * x); -static void real_resize_column (GtkCList * clist, - gint column, - gint width); -static void resize_column (GtkCList * clist, - gint column, - gint width); -static void abort_column_resize (GtkCList *clist); +static void draw_xor_line (GtkCList *clist); +static gint new_column_width (GtkCList *clist, + gint column, + gint *x); +static void column_auto_resize (GtkCList *clist, + GtkCListRow *clist_row, + gint column, + gint old_width); +static void real_resize_column (GtkCList *clist, + gint column, + gint width); +static void abort_column_resize (GtkCList *clist); +static void cell_size_request (GtkCList *clist, + GtkCListRow *clist_row, + gint column, + GtkRequisition *requisition); /* Buttons */ -static void column_button_create (GtkCList * clist, - gint column); -static void column_button_clicked (GtkWidget * widget, - gpointer data); +static void column_button_create (GtkCList *clist, + gint column); +static void column_button_clicked (GtkWidget *widget, + gpointer data); /* Scrollbars */ -static void create_scrollbars (GtkCList * clist); -static void adjust_scrollbars (GtkCList * clist); -static void check_exposures (GtkCList * clist); -static void vadjustment_changed (GtkAdjustment * adjustment, - gpointer data); -static void vadjustment_value_changed (GtkAdjustment * adjustment, - gpointer data); -static void hadjustment_changed (GtkAdjustment * adjustment, - gpointer data); -static void hadjustment_value_changed (GtkAdjustment * adjustment, - gpointer data); +static void create_scrollbars (GtkCList *clist); +static void adjust_scrollbars (GtkCList *clist); +static void check_exposures (GtkCList *clist); +static void vadjustment_changed (GtkAdjustment *adjustment, + gpointer data); +static void vadjustment_value_changed (GtkAdjustment *adjustment, + gpointer data); +static void hadjustment_changed (GtkAdjustment *adjustment, + gpointer data); +static void hadjustment_value_changed (GtkAdjustment *adjustment, + gpointer data); -/* Memory Allocation/Distruction Routines */ -static GtkCListColumn *columns_new (GtkCList * clist); - -static void column_title_new (GtkCList *clist, - gint column, - const gchar *title); -static void columns_delete (GtkCList * clist); - -static GtkCListRow *row_new (GtkCList * clist); - -static void row_delete (GtkCList * clist, - GtkCListRow * clist_row); -static void set_cell_contents (GtkCList *clist, - GtkCListRow *clist_row, - gint column, - GtkCellType type, - const gchar *text, - guint8 spacing, - GdkPixmap *pixmap, - GdkBitmap *mask); -static gint real_insert_row (GtkCList * clist, - gint row, - gchar * text[]); -static void real_remove_row (GtkCList * clist, - gint row); - -/* Focus handling */ -static void gtk_clist_draw_focus (GtkWidget *widget); -static gint gtk_clist_focus_in (GtkWidget *widget, - GdkEventFocus *event); -static gint gtk_clist_focus_out (GtkWidget *widget, - GdkEventFocus *event); -static gint gtk_clist_focus (GtkContainer *container, - GtkDirectionType direction); -static void gtk_clist_set_focus_child (GtkContainer *container, - GtkWidget *child); -static gint gtk_clist_key_press (GtkWidget *widget, - GdkEventKey *event); - -/* Selection handling */ -static void set_anchor (GtkCList *clist, - gboolean add_mode, - gint anchor, - gint undo_anchor); -static void start_selection (GtkCList *clist); -static void end_selection (GtkCList *clist); - -static void toggle_add_mode (GtkCList *clist); -static void toggle_focus_row (GtkCList *clist); -static void move_focus_row (GtkCList *clist, - GtkScrollType scroll_type, - gfloat position); -static void scroll_horizontal (GtkCList *clist, - GtkScrollType scroll_type, - gfloat position); -static void scroll_vertical (GtkCList *clist, - GtkScrollType scroll_type, - gfloat position); -static void extend_selection (GtkCList *clist, - GtkScrollType scroll_type, - gfloat position, - gboolean auto_start_selection); +/* Drawing */ +static void get_cell_style (GtkCList *clist, + GtkCListRow *clist_row, + gint state, + gint column, + GtkStyle **style, + GdkGC **fg_gc, + GdkGC **bg_gc); +static gint draw_cell_pixmap (GdkWindow *window, + GdkRectangle *clip_rectangle, + GdkGC *fg_gc, + GdkPixmap *pixmap, + GdkBitmap *mask, + gint x, + gint y, + gint width, + gint height); +static void draw_row (GtkCList *clist, + GdkRectangle *area, + gint row, + GtkCListRow *clist_row); +static void draw_rows (GtkCList *clist, + GdkRectangle *area); -/* Sorting */ -static gint default_compare (GtkCList *clist, - gconstpointer row1, - gconstpointer row2); -static GList * gtk_clist_merge (GtkCList *clist, - GList *a, - GList *b); -static GList * gtk_clist_mergesort (GtkCList *clist, - GList *list, - gint num); -static void real_sort_list (GtkCList *clist); +/* Size Allocation */ +static void size_allocate_title_buttons (GtkCList *clist); +static void size_allocate_columns (GtkCList *clist); -/* Fill in data after widget is realized and has style */ +/* Memory Allocation/Distruction Routines */ +static GtkCListColumn *columns_new (GtkCList *clist); +static void column_title_new (GtkCList *clist, + gint column, + const gchar *title); +static void columns_delete (GtkCList *clist); +static GtkCListRow *row_new (GtkCList *clist); +static void row_delete (GtkCList *clist, + GtkCListRow *clist_row); +static void set_cell_contents (GtkCList *clist, + GtkCListRow *clist_row, + gint column, + GtkCellType type, + const gchar *text, + guint8 spacing, + GdkPixmap *pixmap, + GdkBitmap *mask); +static gint real_insert_row (GtkCList *clist, + gint row, + gchar *text[]); +static void real_remove_row (GtkCList *clist, + gint row); +static void real_clear (GtkCList *clist); -static void add_style_data (GtkCList * clist); +/* Sorting */ +static gint default_compare (GtkCList *clist, + gconstpointer row1, + gconstpointer row2); +static void real_sort_list (GtkCList *clist); +static GList *gtk_clist_merge (GtkCList *clist, + GList *a, + GList *b); +static GList *gtk_clist_mergesort (GtkCList *clist, + GList *list, + gint num); +/* Misc */ +static gboolean title_focus (GtkCList *clist, + gint dir); static GtkContainerClass *parent_class = NULL; static guint clist_signals[LAST_SIGNAL] = {0}; @@ -422,7 +390,7 @@ gtk_clist_get_type (void) } static void -gtk_clist_class_init (GtkCListClass * klass) +gtk_clist_class_init (GtkCListClass *klass) { GtkObjectClass *object_class; GtkWidgetClass *widget_class; @@ -566,9 +534,11 @@ gtk_clist_class_init (GtkCListClass * klass) widget_class->focus_in_event = gtk_clist_focus_in; widget_class->focus_out_event = gtk_clist_focus_out; widget_class->draw_focus = gtk_clist_draw_focus; + widget_class->style_set = gtk_clist_style_set; /* container_class->add = NULL; use the default GtkContainerClass warning */ - /* container_class->remove = NULL; use the default GtkContainerClass warning */ + /* container_class->remove=NULL; use the default GtkContainerClass warning */ + container_class->forall = gtk_clist_forall; container_class->focus = gtk_clist_focus; container_class->set_focus_child = gtk_clist_set_focus_child; @@ -597,6 +567,7 @@ gtk_clist_class_init (GtkCListClass * klass) klass->end_selection = end_selection; klass->abort_column_resize = abort_column_resize; klass->set_cell_contents = set_cell_contents; + klass->cell_size_request = cell_size_request; klass->scrollbar_spacing = 5; @@ -802,7 +773,7 @@ gtk_clist_class_init (GtkCListClass * klass) } static void -gtk_clist_init (GtkCList * clist) +gtk_clist_init (GtkCList *clist) { clist->flags = 0; @@ -867,9 +838,9 @@ gtk_clist_init (GtkCList * clist) /* Constructors */ void -gtk_clist_construct (GtkCList * clist, - gint columns, - gchar *titles[]) +gtk_clist_construct (GtkCList *clist, + gint columns, + gchar *titles[]) { int i; @@ -885,13 +856,15 @@ gtk_clist_construct (GtkCList * clist, if (!clist->row_mem_chunk) clist->row_mem_chunk = g_mem_chunk_new ("clist row mem chunk", sizeof (GtkCListRow), - sizeof (GtkCListRow) * CLIST_OPTIMUM_SIZE, + sizeof (GtkCListRow) * + CLIST_OPTIMUM_SIZE, G_ALLOC_AND_FREE); if (!clist->cell_mem_chunk) clist->cell_mem_chunk = g_mem_chunk_new ("clist cell mem chunk", sizeof (GtkCell) * columns, - sizeof (GtkCell) * columns * CLIST_OPTIMUM_SIZE, + sizeof (GtkCell) * columns * + CLIST_OPTIMUM_SIZE, G_ALLOC_AND_FREE); /* set number of columns, allocate memory */ @@ -918,26 +891,16 @@ gtk_clist_construct (GtkCList * clist, } } -/* - * GTKCLIST PUBLIC INTERFACE - * gtk_clist_new_with_titles +/* GTKCLIST PUBLIC INTERFACE * gtk_clist_new + * gtk_clist_new_with_titles + * gtk_clist_set_shadow_type + * gtk_clist_set_border *** deprecated function *** + * gtk_clist_set_selection_mode + * gtk_clist_set_policy + * gtk_clist_freeze + * gtk_clist_thaw */ -GtkWidget * -gtk_clist_new_with_titles (gint columns, - gchar * titles[]) -{ - GtkWidget *widget; - - g_return_val_if_fail (titles != NULL, NULL); - - widget = gtk_type_new (GTK_TYPE_CLIST); - - gtk_clist_construct (GTK_CLIST (widget), columns, titles); - - return widget; -} - GtkWidget * gtk_clist_new (gint columns) { @@ -950,23 +913,46 @@ gtk_clist_new (gint columns) gtk_clist_construct (clist, columns, NULL); return GTK_WIDGET (clist); } + +GtkWidget * +gtk_clist_new_with_titles (gint columns, + gchar *titles[]) +{ + GtkWidget *widget; + + g_return_val_if_fail (titles != NULL, NULL); + + widget = gtk_type_new (GTK_TYPE_CLIST); + + gtk_clist_construct (GTK_CLIST (widget), columns, titles); + + return widget; +} void -gtk_clist_set_border (GtkCList * clist, - GtkShadowType border) +gtk_clist_set_shadow_type (GtkCList *clist, + GtkShadowType type) { g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); - clist->shadow_type = border; + clist->shadow_type = type; if (GTK_WIDGET_VISIBLE (clist)) gtk_widget_queue_resize (GTK_WIDGET (clist)); } +/* deprecated function, use gtk_clist_set_shadow_type instead. */ +void +gtk_clist_set_border (GtkCList *clist, + GtkShadowType border) +{ + gtk_clist_set_shadow_type (clist, border); +} + void -gtk_clist_set_selection_mode (GtkCList * clist, - GtkSelectionMode mode) +gtk_clist_set_selection_mode (GtkCList *clist, + GtkSelectionMode mode) { g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); @@ -998,7 +984,32 @@ gtk_clist_set_selection_mode (GtkCList * clist, } void -gtk_clist_freeze (GtkCList * clist) +gtk_clist_set_policy (GtkCList *clist, + GtkPolicyType vscrollbar_policy, + GtkPolicyType hscrollbar_policy) +{ + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); + + if (clist->vscrollbar_policy != vscrollbar_policy) + { + clist->vscrollbar_policy = vscrollbar_policy; + + if (GTK_WIDGET (clist)->parent) + gtk_widget_queue_resize (GTK_WIDGET (clist)); + } + + if (clist->hscrollbar_policy != hscrollbar_policy) + { + clist->hscrollbar_policy = hscrollbar_policy; + + if (GTK_WIDGET (clist)->parent) + gtk_widget_queue_resize (GTK_WIDGET (clist)); + } +} + +void +gtk_clist_freeze (GtkCList *clist) { g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); @@ -1007,7 +1018,7 @@ gtk_clist_freeze (GtkCList * clist) } void -gtk_clist_thaw (GtkCList * clist) +gtk_clist_thaw (GtkCList *clist) { g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); @@ -1018,8 +1029,26 @@ gtk_clist_thaw (GtkCList * clist) draw_rows (clist, NULL); } +/* PUBLIC COLUMN FUNCTIONS + * gtk_clist_column_titles_show + * gtk_clist_column_titles_hide + * gtk_clist_column_title_active + * gtk_clist_column_title_passive + * gtk_clist_column_titles_active + * gtk_clist_column_titles_passive + * gtk_clist_set_column_title + * gtk_clist_set_column_widget + * gtk_clist_set_column_justification + * gtk_clist_set_column_visibility + * gtk_clist_set_column_resizeable + * gtk_clist_set_column_auto_resize + * gtk_clist_optimal_column_width + * gtk_clist_set_column_width + * gtk_clist_set_column_min_width + * gtk_clist_set_column_max_width + */ void -gtk_clist_column_titles_show (GtkCList * clist) +gtk_clist_column_titles_show (GtkCList *clist) { g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); @@ -1034,7 +1063,7 @@ gtk_clist_column_titles_show (GtkCList * clist) } void -gtk_clist_column_titles_hide (GtkCList * clist) +gtk_clist_column_titles_hide (GtkCList *clist) { g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); @@ -1049,107 +1078,8 @@ gtk_clist_column_titles_hide (GtkCList * clist) } void -gtk_clist_set_column_visibility (GtkCList *clist, - gint column, - gboolean visible) -{ - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); - - if (column < 0 || column >= clist->columns) - return; - if (clist->column[column].visible == visible) - return; - - /* don't hide last visible column */ - if (!visible) - { - gint i; - gint vis_columns = 0; - - for (i = 0, vis_columns = 0; i < clist->columns && vis_columns < 2; i++) - if (clist->column[i].visible) - vis_columns++; - - if (vis_columns < 2) - return; - } - - clist->column[column].visible = visible; - if (visible) - gtk_widget_show (clist->column[column].button); - else - gtk_widget_hide (clist->column[column].button); -} - -void -gtk_clist_set_column_resizeable (GtkCList *clist, - gint column, - gint resizeable) -{ - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); - - if (column < 0 || column >= clist->columns) - return; - if (clist->column[column].resizeable == resizeable) - return; - - clist->column[column].resizeable = resizeable; - - if (GTK_WIDGET_VISIBLE (clist)) - size_allocate_title_buttons (clist); -} - -void -gtk_clist_set_column_min_width (GtkCList *clist, - gint column, - gint min_width) -{ - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); - - if (column < 0 || column >= clist->columns) - return; - if (clist->column[column].min_width == min_width) - return; - - if (clist->column[column].max_width >= 0 && - clist->column[column].max_width < min_width) - clist->column[column].min_width = clist->column[column].max_width; - else - clist->column[column].min_width = min_width; - - if (clist->column[column].area.width < clist->column[column].min_width) - gtk_clist_set_column_width (clist, column,clist->column[column].min_width); -} - -void -gtk_clist_set_column_max_width (GtkCList * clist, - gint column, - gint max_width) -{ - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); - - if (column < 0 || column >= clist->columns) - return; - if (clist->column[column].max_width == max_width) - return; - - if (clist->column[column].min_width >= 0 && max_width >= 0 && - clist->column[column].min_width > max_width) - clist->column[column].max_width = clist->column[column].min_width; - else - clist->column[column].max_width = max_width; - - if (clist->column[column].area.width > clist->column[column].max_width) - gtk_clist_set_column_width (clist, column,clist->column[column].max_width); -} - -void -gtk_clist_column_title_active (GtkCList * clist, - gint column) +gtk_clist_column_title_active (GtkCList *clist, + gint column) { g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); @@ -1168,8 +1098,8 @@ gtk_clist_column_title_active (GtkCList * clist, } void -gtk_clist_column_title_passive (GtkCList * clist, - gint column) +gtk_clist_column_title_passive (GtkCList *clist, + gint column) { g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); @@ -1180,14 +1110,15 @@ gtk_clist_column_title_passive (GtkCList * clist, if (GTK_WIDGET_SENSITIVE (clist->column[column].button) || GTK_WIDGET_CAN_FOCUS (clist->column[column].button)) { - GTK_WIDGET_UNSET_FLAGS (clist->column[column].button, GTK_SENSITIVE | GTK_CAN_FOCUS); + GTK_WIDGET_UNSET_FLAGS (clist->column[column].button, + GTK_SENSITIVE | GTK_CAN_FOCUS); if (GTK_WIDGET_VISIBLE (clist)) gtk_widget_queue_draw (clist->column[column].button); } } void -gtk_clist_column_titles_active (GtkCList * clist) +gtk_clist_column_titles_active (GtkCList *clist) { gint i; @@ -1200,7 +1131,7 @@ gtk_clist_column_titles_active (GtkCList * clist) } void -gtk_clist_column_titles_passive (GtkCList * clist) +gtk_clist_column_titles_passive (GtkCList *clist) { gint i; @@ -1276,9 +1207,9 @@ gtk_clist_set_column_title (GtkCList *clist, } void -gtk_clist_set_column_widget (GtkCList * clist, - gint column, - GtkWidget * widget) +gtk_clist_set_column_widget (GtkCList *clist, + gint column, + GtkWidget *widget) { gint new_button = 0; GtkWidget *old_widget; @@ -1318,9 +1249,9 @@ gtk_clist_set_column_widget (GtkCList * clist, } void -gtk_clist_set_column_justification (GtkCList * clist, - gint column, - GtkJustification justification) +gtk_clist_set_column_justification (GtkCList *clist, + gint column, + GtkJustification justification) { GtkWidget *alignment; @@ -1365,436 +1296,594 @@ gtk_clist_set_column_justification (GtkCList * clist, draw_rows (clist, NULL); } -static void -real_resize_column (GtkCList * clist, - gint column, - gint width) +void +gtk_clist_set_column_visibility (GtkCList *clist, + gint column, + gboolean visible) { g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); if (column < 0 || column >= clist->columns) return; + if (clist->column[column].visible == visible) + return; - if (width < MAX (COLUMN_MIN_WIDTH, clist->column[column].min_width)) - width = MAX (COLUMN_MIN_WIDTH, clist->column[column].min_width); - if (clist->column[column].max_width >= 0 && - width > clist->column[column].max_width) - width = clist->column[column].max_width; - - clist->column[column].width = width; - clist->column[column].width_set = TRUE; + /* don't hide last visible column */ + if (!visible) + { + gint i; + gint vis_columns = 0; - /* FIXME: this is quite expensive to do if the widget hasn't - * been size_allocated yet, and pointless. Should - * a flag be kept - */ - size_allocate_columns (clist); - size_allocate_title_buttons (clist); + for (i = 0, vis_columns = 0; i < clist->columns && vis_columns < 2; i++) + if (clist->column[i].visible) + vis_columns++; - if (!GTK_CLIST_FROZEN (clist)) - { - adjust_scrollbars (clist); - draw_rows (clist, NULL); + if (vis_columns < 2) + return; } + + clist->column[column].visible = visible; + if (visible) + gtk_widget_show (clist->column[column].button); + else + gtk_widget_hide (clist->column[column].button); } void -gtk_clist_set_column_width (GtkCList * clist, - gint column, - gint width) +gtk_clist_set_column_resizeable (GtkCList *clist, + gint column, + gint resizeable) { g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); if (column < 0 || column >= clist->columns) return; + if (clist->column[column].resizeable == resizeable) + return; - gtk_signal_emit (GTK_OBJECT (clist), clist_signals[RESIZE_COLUMN], - column, width); + clist->column[column].resizeable = resizeable; + if (resizeable) + clist->column[column].auto_resize = FALSE; + + if (GTK_WIDGET_VISIBLE (clist)) + size_allocate_title_buttons (clist); } void -gtk_clist_set_row_height (GtkCList * clist, - gint height) +gtk_clist_set_column_auto_resize (GtkCList *clist, + gint column, + gboolean auto_resize) { - gint text_height; - g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); - if (height > 0) - clist->row_height = height; - else + if (column < 0 || column >= clist->columns) + return; + if (clist->column[column].auto_resize == auto_resize) return; - GTK_CLIST_SET_FLAG (clist, CLIST_ROW_HEIGHT_SET); - - if (GTK_WIDGET_REALIZED (clist)) + clist->column[column].auto_resize = auto_resize; + if (auto_resize) { - text_height = height - (GTK_WIDGET (clist)->style->font->ascent + - GTK_WIDGET (clist) ->style->font->descent + 1); - clist->row_center_offset = ((text_height / 2) + 1.5 + - GTK_WIDGET (clist)->style->font->ascent); + clist->column[column].resizeable = FALSE; + if (!GTK_CLIST_AUTO_RESIZE_BLOCKED (clist)) + { + gint width; + + width = gtk_clist_optimal_column_width (clist, column); + gtk_clist_set_column_width (clist, column, width); + } } - - if (!GTK_CLIST_FROZEN (clist)) + + if (GTK_WIDGET_VISIBLE (clist)) + size_allocate_title_buttons (clist); +} + +gint +gtk_clist_optimal_column_width (GtkCList *clist, + gint column) +{ + GtkRequisition requisition; + GList *list; + gint width = 0; + + g_return_val_if_fail (clist != NULL, 0); + g_return_val_if_fail (GTK_CLIST (clist), 0); + + if (column < 0 || column > clist->columns) + return 0; + + for (list = clist->row_list; list; list = list->next) { - adjust_scrollbars (clist); - draw_rows (clist, NULL); + GTK_CLIST_CLASS_FW (clist)->cell_size_request + (clist, GTK_CLIST_ROW (list), column, &requisition); + width = MAX (width, requisition.width); } + + return width; } void -gtk_clist_moveto (GtkCList * clist, - gint row, - gint column, - gfloat row_align, - gfloat col_align) +gtk_clist_set_column_width (GtkCList *clist, + gint column, + gint width) { g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); - if (row < -1 || row >= clist->rows) - return; - if (column < -1 || column >= clist->columns) + if (column < 0 || column >= clist->columns) return; - row_align = CLAMP (row_align, 0, 1); - col_align = CLAMP (col_align, 0, 1); - - /* adjust horizontal scrollbar */ - if (column >= 0) - { - GtkAdjustment *adj; - gint x; - - adj = GTK_RANGE (clist->hscrollbar)->adjustment; - - x = COLUMN_LEFT (clist, column) - CELL_SPACING - COLUMN_INSET - - (col_align * (clist->clist_window_width - 2 * COLUMN_INSET - - CELL_SPACING - clist->column[column].area.width)); - if (x < 0) - gtk_adjustment_set_value (adj, 0.0); - else if (x > LIST_WIDTH (clist) - clist->clist_window_width) - gtk_adjustment_set_value - (adj, LIST_WIDTH (clist) - clist->clist_window_width); - else - gtk_adjustment_set_value (adj, x); - } - - /* adjust vertical scrollbar */ - if (row >= 0) - move_vertical (clist, row, row_align); + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[RESIZE_COLUMN], + column, width); } -GtkCellType -gtk_clist_get_cell_type (GtkCList * clist, - gint row, - gint column) +void +gtk_clist_set_column_min_width (GtkCList *clist, + gint column, + gint min_width) { - GtkCListRow *clist_row; - - g_return_val_if_fail (clist != NULL, -1); - g_return_val_if_fail (GTK_IS_CLIST (clist), -1); + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); - if (row < 0 || row >= clist->rows) - return -1; if (column < 0 || column >= clist->columns) - return -1; + return; + if (clist->column[column].min_width == min_width) + return; - clist_row = (g_list_nth (clist->row_list, row))->data; + if (clist->column[column].max_width >= 0 && + clist->column[column].max_width < min_width) + clist->column[column].min_width = clist->column[column].max_width; + else + clist->column[column].min_width = min_width; - return clist_row->cell[column].type; + if (clist->column[column].area.width < clist->column[column].min_width) + gtk_clist_set_column_width (clist, column,clist->column[column].min_width); } void -gtk_clist_set_text (GtkCList *clist, - gint row, - gint column, - const gchar *text) +gtk_clist_set_column_max_width (GtkCList *clist, + gint column, + gint max_width) { - GtkCListRow *clist_row; - g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); - if (row < 0 || row >= clist->rows) - return; if (column < 0 || column >= clist->columns) return; + if (clist->column[column].max_width == max_width) + return; - clist_row = (g_list_nth (clist->row_list, row))->data; - - /* if text is null, then the cell is empty */ - GTK_CLIST_CLASS_FW (clist)->set_cell_contents - (clist, clist_row, column, GTK_CELL_TEXT, text, 0, NULL, NULL); - - /* redraw the list if it's not frozen */ - if (!GTK_CLIST_FROZEN (clist)) - { - if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE) - GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row); - } + if (clist->column[column].min_width >= 0 && max_width >= 0 && + clist->column[column].min_width > max_width) + clist->column[column].max_width = clist->column[column].min_width; + else + clist->column[column].max_width = max_width; + + if (clist->column[column].area.width > clist->column[column].max_width) + gtk_clist_set_column_width (clist, column,clist->column[column].max_width); } -gint -gtk_clist_get_text (GtkCList * clist, - gint row, - gint column, - gchar ** text) +/* PRIVATE COLUMN FUNCTIONS + * column_auto_resize + * real_resize_column + * abort_column_resize + * size_allocate_title_buttons + * size_allocate_columns + * new_column_width + * column_button_create + * column_button_clicked + */ +static void +column_auto_resize (GtkCList *clist, + GtkCListRow *clist_row, + gint column, + gint old_width) { - GtkCListRow *clist_row; - - g_return_val_if_fail (clist != NULL, 0); - g_return_val_if_fail (GTK_IS_CLIST (clist), 0); - - if (row < 0 || row >= clist->rows) - return 0; - if (column < 0 || column >= clist->columns) - return 0; + /* resize column if needed for auto_resize */ + GtkRequisition requisition; - clist_row = (g_list_nth (clist->row_list, row))->data; + if (!clist->column[column].auto_resize || + GTK_CLIST_AUTO_RESIZE_BLOCKED (clist)) + return; - if (clist_row->cell[column].type != GTK_CELL_TEXT) - return 0; + GTK_CLIST_CLASS_FW (clist)->cell_size_request (clist, clist_row, + column, &requisition); - if (text) - *text = GTK_CELL_TEXT (clist_row->cell[column])->text; + if (requisition.width > clist->column[column].width) + { + if (clist->column[column].max_width < 0) + gtk_clist_set_column_width (clist, column, requisition.width); + else if (clist->column[column].max_width > + clist->column[column].width) + gtk_clist_set_column_width (clist, column, + MIN (requisition.width, + clist->column[column].max_width)); + } + else if (requisition.width < old_width && + old_width == clist->column[column].width) + { + GList *list; + gint new_width = 0; - return 1; + /* run a "gtk_clist_optimal_column_width" but break, if + * the column doesn't shrink */ + new_width = 0; + for (list = clist->row_list; list; list = list->next) + { + GTK_CLIST_CLASS_FW (clist)->cell_size_request + (clist, GTK_CLIST_ROW (list), column, &requisition); + new_width = MAX (new_width, requisition.width); + if (new_width == clist->column[column].width) + break; + } + if (new_width < clist->column[column].width) + gtk_clist_set_column_width + (clist, column, MAX (new_width, clist->column[column].min_width)); + } } -void -gtk_clist_set_pixmap (GtkCList * clist, - gint row, - gint column, - GdkPixmap * pixmap, - GdkBitmap * mask) +static void +real_resize_column (GtkCList *clist, + gint column, + gint width) { - GtkCListRow *clist_row; - g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); - if (row < 0 || row >= clist->rows) - return; if (column < 0 || column >= clist->columns) return; - clist_row = (g_list_nth (clist->row_list, row))->data; - - gdk_pixmap_ref (pixmap); - - if (mask) gdk_pixmap_ref (mask); + if (width < MAX (COLUMN_MIN_WIDTH, clist->column[column].min_width)) + width = MAX (COLUMN_MIN_WIDTH, clist->column[column].min_width); + if (clist->column[column].max_width >= 0 && + width > clist->column[column].max_width) + width = clist->column[column].max_width; - GTK_CLIST_CLASS_FW (clist)->set_cell_contents - (clist, clist_row, column, GTK_CELL_PIXMAP, NULL, 0, pixmap, mask); + clist->column[column].width = width; + clist->column[column].width_set = TRUE; + + /* FIXME: this is quite expensive to do if the widget hasn't + * been size_allocated yet, and pointless. Should + * a flag be kept + */ + size_allocate_columns (clist); + size_allocate_title_buttons (clist); - /* redraw the list if it's not frozen */ if (!GTK_CLIST_FROZEN (clist)) { - if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE) - GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row); + adjust_scrollbars (clist); + draw_rows (clist, NULL); } } -gint -gtk_clist_get_pixmap (GtkCList * clist, - gint row, - gint column, - GdkPixmap ** pixmap, - GdkBitmap ** mask) -{ - GtkCListRow *clist_row; - - g_return_val_if_fail (clist != NULL, 0); - g_return_val_if_fail (GTK_IS_CLIST (clist), 0); - - if (row < 0 || row >= clist->rows) - return 0; - if (column < 0 || column >= clist->columns) - return 0; - - clist_row = (g_list_nth (clist->row_list, row))->data; - - if (clist_row->cell[column].type != GTK_CELL_PIXMAP) - return 0; - - if (pixmap) - { - *pixmap = GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap; - /* mask can be NULL */ - *mask = GTK_CELL_PIXMAP (clist_row->cell[column])->mask; - } - - return 1; -} - -void -gtk_clist_set_pixtext (GtkCList *clist, - gint row, - gint column, - const gchar *text, - guint8 spacing, - GdkPixmap *pixmap, - GdkBitmap *mask) +static void +abort_column_resize (GtkCList *clist) { - GtkCListRow *clist_row; - g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); - if (row < 0 || row >= clist->rows) - return; - if (column < 0 || column >= clist->columns) + if (!GTK_CLIST_IN_DRAG (clist)) return; - clist_row = (g_list_nth (clist->row_list, row))->data; - - gdk_pixmap_ref (pixmap); - if (mask) gdk_pixmap_ref (mask); - GTK_CLIST_CLASS_FW (clist)->set_cell_contents - (clist, clist_row, column, GTK_CELL_PIXTEXT, text, spacing, pixmap, mask); + GTK_CLIST_UNSET_FLAG (clist, CLIST_IN_DRAG); + gtk_grab_remove (GTK_WIDGET (clist)); + gdk_pointer_ungrab (GDK_CURRENT_TIME); + clist->drag_pos = -1; - /* redraw the list if it's not frozen */ - if (!GTK_CLIST_FROZEN (clist)) + if (clist->x_drag >= 0 && clist->x_drag <= clist->clist_window_width - 1) + draw_xor_line (clist); + + if (GTK_CLIST_ADD_MODE (clist)) { - if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE) - GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row); + gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_ON_OFF_DASH, 0,0); + gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2); } } -gint -gtk_clist_get_pixtext (GtkCList * clist, - gint row, - gint column, - gchar ** text, - guint8 * spacing, - GdkPixmap ** pixmap, - GdkBitmap ** mask) +static void +size_allocate_title_buttons (GtkCList *clist) { - GtkCListRow *clist_row; + GtkAllocation button_allocation; + gint last_column; + gint last_button = 0; + gint i; - g_return_val_if_fail (clist != NULL, 0); - g_return_val_if_fail (GTK_IS_CLIST (clist), 0); + if (!GTK_WIDGET_REALIZED (clist)) + return; - if (row < 0 || row >= clist->rows) - return 0; - if (column < 0 || column >= clist->columns) - return 0; + button_allocation.x = clist->hoffset; + button_allocation.y = 0; + button_allocation.width = 0; + button_allocation.height = clist->column_title_area.height; - clist_row = (g_list_nth (clist->row_list, row))->data; + /* find last visible column */ + for (last_column = clist->columns - 1; last_column >= 0; last_column--) + if (clist->column[last_column].visible) + break; - if (clist_row->cell[column].type != GTK_CELL_PIXTEXT) - return 0; + for (i = 0; i < last_column; i++) + { + if (!clist->column[i].visible) + { + last_button = i + 1; + gdk_window_hide (clist->column[i].window); + continue; + } - if (text) - *text = GTK_CELL_PIXTEXT (clist_row->cell[column])->text; - if (spacing) - *spacing = GTK_CELL_PIXTEXT (clist_row->cell[column])->spacing; - if (pixmap) - *pixmap = GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap; + button_allocation.width += (clist->column[i].area.width + + CELL_SPACING + 2 * COLUMN_INSET); - /* mask can be NULL */ - *mask = GTK_CELL_PIXTEXT (clist_row->cell[column])->mask; + if (!clist->column[i + 1].button) + { + gdk_window_hide (clist->column[i].window); + continue; + } - return 1; + gtk_widget_size_allocate (clist->column[last_button].button, + &button_allocation); + button_allocation.x += button_allocation.width; + button_allocation.width = 0; + + if (clist->column[last_button].resizeable) + { + gdk_window_show (clist->column[last_button].window); + gdk_window_move_resize (clist->column[last_button].window, + button_allocation.x - (DRAG_WIDTH / 2), + 0, DRAG_WIDTH, + clist->column_title_area.height); + } + else + gdk_window_hide (clist->column[last_button].window); + + last_button = i + 1; + } + + button_allocation.width += (clist->column[last_column].area.width + + 2 * (CELL_SPACING + COLUMN_INSET)); + gtk_widget_size_allocate (clist->column[last_button].button, + &button_allocation); + + if (clist->column[last_button].resizeable) + { + button_allocation.x += button_allocation.width; + + gdk_window_show (clist->column[last_button].window); + gdk_window_move_resize (clist->column[last_button].window, + button_allocation.x - (DRAG_WIDTH / 2), + 0, DRAG_WIDTH, clist->column_title_area.height); + } + else + gdk_window_hide (clist->column[last_button].window); } -void -gtk_clist_set_foreground (GtkCList * clist, - gint row, - GdkColor * color) +static void +size_allocate_columns (GtkCList *clist) { - GtkCListRow *clist_row; + gint xoffset = CELL_SPACING + COLUMN_INSET; + gint last_column; + gint width = 0; + gint i; - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); + /* find last visible column and calculate correct column width */ + for (last_column = clist->columns - 1; + last_column >= 0 && !clist->column[last_column].visible; last_column--); - if (row < 0 || row >= clist->rows) + if (last_column < 0) return; - clist_row = (g_list_nth (clist->row_list, row))->data; + for (i = 0; i < last_column; i++) + { + if (!clist->column[i].visible) + continue; + clist->column[i].area.x = xoffset; + clist->column[i].area.width = clist->column[i].width; + xoffset += clist->column[i].width + CELL_SPACING + (2 * COLUMN_INSET); + } - if (color) + if (clist->column[i].width_set) + width = clist->column[i].width; + else if (clist->column[i].title) + width = gdk_string_width (GTK_WIDGET (clist)->style->font, + clist->column[i].title); + + clist->column[i].area.x = xoffset; + clist->column[i].area.width = MAX (width, + clist->clist_window_width - xoffset - + (CELL_SPACING + COLUMN_INSET)); +} + +/* this function returns the new width of the column being resized given + * the column and x position of the cursor; the x cursor position is passed + * in as a pointer and automagicly corrected if it's beyond min/max limits */ +static gint +new_column_width (GtkCList *clist, + gint column, + gint *x) +{ + gint xthickness = GTK_WIDGET (clist)->style->klass->xthickness; + gint width; + gint cx; + gint dx; + + /* first translate the x position from widget->window + * to clist->clist_window */ + cx = *x - xthickness; + + /* calculate new column width making sure it doesn't end up + * less than the minimum width */ + dx = (COLUMN_LEFT_XPIXEL (clist, column) + COLUMN_INSET + + (column < clist->columns - 1) * CELL_SPACING); + width = cx - dx; + + if (width < MAX (COLUMN_MIN_WIDTH, clist->column[column].min_width)) { - clist_row->foreground = *color; - clist_row->fg_set = TRUE; - if (GTK_WIDGET_REALIZED (clist)) - gdk_color_alloc (gtk_widget_get_colormap (GTK_WIDGET (clist)), - &clist_row->foreground); + width = MAX (COLUMN_MIN_WIDTH, clist->column[column].min_width); + cx = dx + width; + *x = cx + xthickness; } - else - clist_row->fg_set = FALSE; + else if (clist->column[column].max_width >= COLUMN_MIN_WIDTH && + width > clist->column[column].max_width) + { + width = clist->column[column].max_width; + cx = dx + clist->column[column].max_width; + *x = cx + xthickness; + } - if (!GTK_CLIST_FROZEN (clist) - && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)) - GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row); + if (cx < 0 || cx > clist->clist_window_width) + *x = -1; + + return width; +} + +static void +column_button_create (GtkCList *clist, + gint column) +{ + GtkWidget *button; + + button = clist->column[column].button = gtk_button_new (); + if (GTK_WIDGET_REALIZED (clist) && clist->title_window) + gtk_widget_set_parent_window (clist->column[column].button, clist->title_window); + gtk_widget_set_parent (button, GTK_WIDGET (clist)); + + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) column_button_clicked, + (gpointer) clist); + + gtk_widget_show (button); +} + +static void +column_button_clicked (GtkWidget *widget, + gpointer data) +{ + gint i; + GtkCList *clist; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CLIST (data)); + + clist = GTK_CLIST (data); + + /* find the column who's button was pressed */ + for (i = 0; i < clist->columns; i++) + if (clist->column[i].button == widget) + break; + + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[CLICK_COLUMN], i); } void -gtk_clist_set_background (GtkCList * clist, - gint row, - GdkColor * color) +gtk_clist_set_row_height (GtkCList *clist, + gint height) { - GtkCListRow *clist_row; + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); + + if (height > 0) + clist->row_height = height; + else + return; + + GTK_CLIST_SET_FLAG (clist, CLIST_ROW_HEIGHT_SET); + + if (GTK_WIDGET_REALIZED (clist)) + { + GdkFont *font; + + font = GTK_WIDGET (clist)->style->font; + clist->row_center_offset = (((height + font->ascent - font->descent - 1) + / 2) + 1.5); + } + + if (!GTK_CLIST_FROZEN (clist)) + { + adjust_scrollbars (clist); + draw_rows (clist, NULL); + } +} +void +gtk_clist_moveto (GtkCList *clist, + gint row, + gint column, + gfloat row_align, + gfloat col_align) +{ g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); - if (row < 0 || row >= clist->rows) + if (row < -1 || row >= clist->rows) + return; + if (column < -1 || column >= clist->columns) return; - clist_row = (g_list_nth (clist->row_list, row))->data; + row_align = CLAMP (row_align, 0, 1); + col_align = CLAMP (col_align, 0, 1); - if (color) + /* adjust horizontal scrollbar */ + if (column >= 0) { - clist_row->background = *color; - clist_row->bg_set = TRUE; - if (GTK_WIDGET_REALIZED (clist)) - gdk_color_alloc (gtk_widget_get_colormap (GTK_WIDGET (clist)), - &clist_row->background); + GtkAdjustment *adj; + gint x; + + adj = GTK_RANGE (clist->hscrollbar)->adjustment; + + x = (COLUMN_LEFT (clist, column) - CELL_SPACING - COLUMN_INSET - + (col_align * (clist->clist_window_width - 2 * COLUMN_INSET - + CELL_SPACING - clist->column[column].area.width))); + if (x < 0) + gtk_adjustment_set_value (adj, 0.0); + else if (x > LIST_WIDTH (clist) - clist->clist_window_width) + gtk_adjustment_set_value + (adj, LIST_WIDTH (clist) - clist->clist_window_width); + else + gtk_adjustment_set_value (adj, x); } - else - clist_row->bg_set = FALSE; - if (!GTK_CLIST_FROZEN (clist) - && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)) - GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row); + /* adjust vertical scrollbar */ + if (row >= 0) + move_vertical (clist, row, row_align); } -void -gtk_clist_set_shift (GtkCList * clist, - gint row, - gint column, - gint vertical, - gint horizontal) +/* PUBLIC CELL FUNCTIONS + * gtk_clist_get_cell_type + * gtk_clist_set_text + * gtk_clist_get_text + * gtk_clist_set_pixmap + * gtk_clist_get_pixmap + * gtk_clist_set_pixtext + * gtk_clist_get_pixtext + * gtk_clist_set_shift + */ +GtkCellType +gtk_clist_get_cell_type (GtkCList *clist, + gint row, + gint column) { GtkCListRow *clist_row; - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); + g_return_val_if_fail (clist != NULL, -1); + g_return_val_if_fail (GTK_IS_CLIST (clist), -1); if (row < 0 || row >= clist->rows) - return; + return -1; if (column < 0 || column >= clist->columns) - return; + return -1; clist_row = (g_list_nth (clist->row_list, row))->data; - clist_row->cell[column].vertical = vertical; - clist_row->cell[column].horizontal = horizontal; - - if (!GTK_CLIST_FROZEN (clist) - && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)) - GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row); + return clist_row->cell[column].type; } void -gtk_clist_set_selectable (GtkCList *clist, - gint row, - gboolean selectable) +gtk_clist_set_text (GtkCList *clist, + gint row, + gint column, + const gchar *text) { GtkCListRow *clist_row; @@ -1803,421 +1892,663 @@ gtk_clist_set_selectable (GtkCList *clist, if (row < 0 || row >= clist->rows) return; + if (column < 0 || column >= clist->columns) + return; clist_row = (g_list_nth (clist->row_list, row))->data; - if (selectable == clist_row->selectable) - return; - - clist_row->selectable = selectable; + /* if text is null, then the cell is empty */ + GTK_CLIST_CLASS_FW (clist)->set_cell_contents + (clist, clist_row, column, GTK_CELL_TEXT, text, 0, NULL, NULL); - if (!selectable && clist_row->state == GTK_STATE_SELECTED) + /* redraw the list if it's not frozen */ + if (!GTK_CLIST_FROZEN (clist)) { - if (clist->anchor >= 0 && - clist->selection_mode == GTK_SELECTION_EXTENDED) - { - if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_FOCUS (clist))) - { - GTK_CLIST_UNSET_FLAG (clist, CLIST_DRAG_SELECTION); - gtk_grab_remove (GTK_WIDGET (clist)); - gdk_pointer_ungrab (GDK_CURRENT_TIME); - if (clist->htimer) - { - gtk_timeout_remove (clist->htimer); - clist->htimer = 0; - } - if (clist->vtimer) - { - gtk_timeout_remove (clist->vtimer); - clist->vtimer = 0; - } - } - GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL); - } - unselect_row (clist, row, -1, NULL); - } + if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE) + GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row); + } } -gboolean -gtk_clist_get_selectable (GtkCList *clist, - gint row) +gint +gtk_clist_get_text (GtkCList *clist, + gint row, + gint column, + gchar **text) { - g_return_val_if_fail (clist != NULL, FALSE); - g_return_val_if_fail (GTK_IS_CLIST (clist), FALSE); + GtkCListRow *clist_row; + + g_return_val_if_fail (clist != NULL, 0); + g_return_val_if_fail (GTK_IS_CLIST (clist), 0); if (row < 0 || row >= clist->rows) - return FALSE; + return 0; + if (column < 0 || column >= clist->columns) + return 0; - return GTK_CLIST_ROW (g_list_nth (clist->row_list, row))->selectable; -} + clist_row = (g_list_nth (clist->row_list, row))->data; -gint -gtk_clist_prepend (GtkCList *clist, - gchar *text[]) -{ - g_return_val_if_fail (clist != NULL, -1); - g_return_val_if_fail (GTK_IS_CLIST (clist), -1); - g_return_val_if_fail (text != NULL, -1); + if (clist_row->cell[column].type != GTK_CELL_TEXT) + return 0; - return GTK_CLIST_CLASS_FW (clist)->insert_row (clist, 0, text); + if (text) + *text = GTK_CELL_TEXT (clist_row->cell[column])->text; + + return 1; } -gint -gtk_clist_append (GtkCList *clist, - gchar *text[]) +void +gtk_clist_set_pixmap (GtkCList *clist, + gint row, + gint column, + GdkPixmap *pixmap, + GdkBitmap *mask) { - g_return_val_if_fail (clist != NULL, -1); - g_return_val_if_fail (GTK_IS_CLIST (clist), -1); - g_return_val_if_fail (text != NULL, -1); + GtkCListRow *clist_row; - return GTK_CLIST_CLASS_FW (clist)->insert_row (clist, clist->rows, text); -} + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); -gint -gtk_clist_insert (GtkCList *clist, - gint row, - gchar *text[]) -{ - g_return_val_if_fail (clist != NULL, -1); - g_return_val_if_fail (GTK_IS_CLIST (clist), -1); - g_return_val_if_fail (text != NULL, -1); + if (row < 0 || row >= clist->rows) + return; + if (column < 0 || column >= clist->columns) + return; - if (row < 0 || row > clist->rows) - row = clist->rows; + clist_row = (g_list_nth (clist->row_list, row))->data; + + gdk_pixmap_ref (pixmap); + + if (mask) gdk_pixmap_ref (mask); + + GTK_CLIST_CLASS_FW (clist)->set_cell_contents + (clist, clist_row, column, GTK_CELL_PIXMAP, NULL, 0, pixmap, mask); - return GTK_CLIST_CLASS_FW (clist)->insert_row (clist, row, text); + /* redraw the list if it's not frozen */ + if (!GTK_CLIST_FROZEN (clist)) + { + if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE) + GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row); + } } -static gint -real_insert_row (GtkCList *clist, - gint row, - gchar *text[]) +gint +gtk_clist_get_pixmap (GtkCList *clist, + gint row, + gint column, + GdkPixmap **pixmap, + GdkBitmap **mask) { - gint i; GtkCListRow *clist_row; - g_return_val_if_fail (clist != NULL, -1); - g_return_val_if_fail (GTK_IS_CLIST (clist), -1); - g_return_val_if_fail (text != NULL, -1); + g_return_val_if_fail (clist != NULL, 0); + g_return_val_if_fail (GTK_IS_CLIST (clist), 0); - /* return if out of bounds */ - if (row < 0 || row > clist->rows) - return -1; + if (row < 0 || row >= clist->rows) + return 0; + if (column < 0 || column >= clist->columns) + return 0; - /* create the row */ - clist_row = row_new (clist); + clist_row = (g_list_nth (clist->row_list, row))->data; - /* set the text in the row's columns */ - for (i = 0; i < clist->columns; i++) - if (text[i]) - GTK_CLIST_CLASS_FW (clist)->set_cell_contents - (clist, clist_row, i, GTK_CELL_TEXT, text[i], 0, NULL ,NULL); + if (clist_row->cell[column].type != GTK_CELL_PIXMAP) + return 0; - if (!clist->rows) - { - clist->row_list = g_list_append (clist->row_list, clist_row); - clist->row_list_end = clist->row_list; - } - else - { - if (GTK_CLIST_AUTO_SORT (clist)) /* override insertion pos */ - { - GList *work; - - row = 0; - work = clist->row_list; - - if (clist->sort_type == GTK_SORT_ASCENDING) - { - while (row < clist->rows && - clist->compare (clist, clist_row, - GTK_CLIST_ROW (work)) > 0) - { - row++; - work = work->next; - } - } - else - { - while (row < clist->rows && - clist->compare (clist, clist_row, - GTK_CLIST_ROW (work)) < 0) - { - row++; - work = work->next; - } - } - } - - /* reset the row end pointer if we're inserting at the end of the list */ - if (row == clist->rows) - clist->row_list_end = (g_list_append (clist->row_list_end, clist_row))->next; - else - clist->row_list = g_list_insert (clist->row_list, clist_row, row); - } - - clist->rows++; + if (pixmap) + { + *pixmap = GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap; + /* mask can be NULL */ + *mask = GTK_CELL_PIXMAP (clist_row->cell[column])->mask; + } - if (row < ROW_FROM_YPIXEL (clist, 0)) - clist->voffset -= (clist->row_height + CELL_SPACING); + return 1; +} - /* syncronize the selection list */ - sync_selection (clist, row, SYNC_INSERT); +void +gtk_clist_set_pixtext (GtkCList *clist, + gint row, + gint column, + const gchar *text, + guint8 spacing, + GdkPixmap *pixmap, + GdkBitmap *mask) +{ + GtkCListRow *clist_row; - /* redraw the list if it isn't frozen */ + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); + + if (row < 0 || row >= clist->rows) + return; + if (column < 0 || column >= clist->columns) + return; + + clist_row = (g_list_nth (clist->row_list, row))->data; + + gdk_pixmap_ref (pixmap); + if (mask) gdk_pixmap_ref (mask); + GTK_CLIST_CLASS_FW (clist)->set_cell_contents + (clist, clist_row, column, GTK_CELL_PIXTEXT, text, spacing, pixmap, mask); + + /* redraw the list if it's not frozen */ if (!GTK_CLIST_FROZEN (clist)) { - adjust_scrollbars (clist); - if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE) - draw_rows (clist, NULL); + GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row); } - - return row; } -void -gtk_clist_remove (GtkCList * clist, - gint row) +gint +gtk_clist_get_pixtext (GtkCList *clist, + gint row, + gint column, + gchar **text, + guint8 *spacing, + GdkPixmap **pixmap, + GdkBitmap **mask) { - GTK_CLIST_CLASS_FW (clist)->remove_row (clist, row); + GtkCListRow *clist_row; + + g_return_val_if_fail (clist != NULL, 0); + g_return_val_if_fail (GTK_IS_CLIST (clist), 0); + + if (row < 0 || row >= clist->rows) + return 0; + if (column < 0 || column >= clist->columns) + return 0; + + clist_row = (g_list_nth (clist->row_list, row))->data; + + if (clist_row->cell[column].type != GTK_CELL_PIXTEXT) + return 0; + + if (text) + *text = GTK_CELL_PIXTEXT (clist_row->cell[column])->text; + if (spacing) + *spacing = GTK_CELL_PIXTEXT (clist_row->cell[column])->spacing; + if (pixmap) + *pixmap = GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap; + + /* mask can be NULL */ + *mask = GTK_CELL_PIXTEXT (clist_row->cell[column])->mask; + + return 1; } -static void -real_remove_row (GtkCList * clist, - gint row) +void +gtk_clist_set_shift (GtkCList *clist, + gint row, + gint column, + gint vertical, + gint horizontal) { - gint was_visible, was_selected; - GList *list; + GtkRequisition requisition; GtkCListRow *clist_row; g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); - /* return if out of bounds */ - if (row < 0 || row > (clist->rows - 1)) + if (row < 0 || row >= clist->rows) + return; + if (column < 0 || column >= clist->columns) return; - was_visible = (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE); - was_selected = 0; + clist_row = (g_list_nth (clist->row_list, row))->data; - /* get the row we're going to delete */ - list = g_list_nth (clist->row_list, row); - clist_row = list->data; + if (clist->column[column].auto_resize && + !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist)) + GTK_CLIST_CLASS_FW (clist)->cell_size_request (clist, clist_row, + column, &requisition); - /* if we're removing a selected row, we have to make sure - * it's properly unselected, and then sync up the clist->selected - * list to reflect the deincrimented indexies of rows after the - * removal */ - if (clist_row->state == GTK_STATE_SELECTED) - { - switch (clist->selection_mode) - { - case GTK_SELECTION_SINGLE: - case GTK_SELECTION_MULTIPLE: - case GTK_SELECTION_EXTENDED: - unselect_row (clist, row, -1, NULL); - break; - - case GTK_SELECTION_BROWSE: - select_row (clist, row - 1, -1, NULL); - break; + clist_row->cell[column].vertical = vertical; + clist_row->cell[column].horizontal = horizontal; - default: - break; - } - } + column_auto_resize (clist, clist_row, column, requisition.width); - /* reset the row end pointer if we're removing at the - * end of the list */ - if (row == clist->rows - 1) - clist->row_list_end = list->prev; - if (row >= clist->focus_row && clist->focus_row >=0) - clist->focus_row--; + if (!GTK_CLIST_FROZEN (clist) + && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)) + GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row); +} - clist->row_list = g_list_remove (clist->row_list, clist_row); - clist->rows--; - - if (row < ROW_FROM_YPIXEL (clist, 0)) - clist->voffset += clist->row_height + CELL_SPACING; +/* PRIVATE CELL FUNCTIONS + * set_cell_contents + * cell_size_request + */ +static void +set_cell_contents (GtkCList *clist, + GtkCListRow *clist_row, + gint column, + GtkCellType type, + const gchar *text, + guint8 spacing, + GdkPixmap *pixmap, + GdkBitmap *mask) +{ + GtkRequisition requisition; - sync_selection (clist, row, SYNC_REMOVE); + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); + g_return_if_fail (clist_row != NULL); - /* toast the row */ - row_delete (clist, clist_row); + if (clist->column[column].auto_resize && + !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist)) + GTK_CLIST_CLASS_FW (clist)->cell_size_request (clist, clist_row, + column, &requisition); - /* redraw the row if it isn't frozen */ - if (!GTK_CLIST_FROZEN (clist)) + switch (clist_row->cell[column].type) { - adjust_scrollbars (clist); - - if (was_visible) - draw_rows (clist, NULL); + case GTK_CELL_EMPTY: + break; + case GTK_CELL_TEXT: + g_free (GTK_CELL_TEXT (clist_row->cell[column])->text); + break; + case GTK_CELL_PIXMAP: + gdk_pixmap_unref (GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap); + if (GTK_CELL_PIXMAP (clist_row->cell[column])->mask) + gdk_bitmap_unref (GTK_CELL_PIXMAP (clist_row->cell[column])->mask); + break; + case GTK_CELL_PIXTEXT: + g_free (GTK_CELL_PIXTEXT (clist_row->cell[column])->text); + gdk_pixmap_unref (GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap); + if (GTK_CELL_PIXTEXT (clist_row->cell[column])->mask) + gdk_bitmap_unref (GTK_CELL_PIXTEXT (clist_row->cell[column])->mask); + break; + case GTK_CELL_WIDGET: + /* unimplimented */ + break; + default: + break; } -} -static void -sync_selection (GtkCList * clist, - gint row, - gint mode) -{ - GList *list; - gint d; + clist_row->cell[column].type = GTK_CELL_EMPTY; - if (mode == SYNC_INSERT) - d = 1; - else - d = -1; - - if (clist->focus_row >= row) + switch (type) { - clist->focus_row += d; - if (clist->focus_row == -1 && clist->rows >= 1) - clist->focus_row = 0; + case GTK_CELL_TEXT: + if (text) + { + clist_row->cell[column].type = GTK_CELL_TEXT; + GTK_CELL_TEXT (clist_row->cell[column])->text = g_strdup (text); + } + break; + case GTK_CELL_PIXMAP: + if (pixmap) + { + clist_row->cell[column].type = GTK_CELL_PIXMAP; + GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap = pixmap; + /* We set the mask even if it is NULL */ + GTK_CELL_PIXMAP (clist_row->cell[column])->mask = mask; + } + break; + case GTK_CELL_PIXTEXT: + if (text && pixmap) + { + clist_row->cell[column].type = GTK_CELL_PIXTEXT; + GTK_CELL_PIXTEXT (clist_row->cell[column])->text = g_strdup (text); + GTK_CELL_PIXTEXT (clist_row->cell[column])->spacing = spacing; + GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap = pixmap; + GTK_CELL_PIXTEXT (clist_row->cell[column])->mask = mask; + } + break; + default: + break; } - if (clist->selection_mode == GTK_SELECTION_BROWSE && clist->anchor != -1) - GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL); + column_auto_resize (clist, clist_row, column, requisition.width); +} - g_list_free (clist->undo_selection); - g_list_free (clist->undo_unselection); - clist->undo_selection = NULL; - clist->undo_unselection = NULL; +static void +cell_size_request (GtkCList *clist, + GtkCListRow *clist_row, + gint column, + GtkRequisition *requisition) +{ + GtkStyle *style; + gint width; + gint height; - clist->anchor = -1; - clist->drag_pos = -1; - clist->undo_anchor = clist->focus_row; + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); + g_return_if_fail (requisition != NULL); - list = clist->selection; - while (list) + get_cell_style (clist, clist_row, GTK_STATE_PRELIGHT, column, &style, + NULL, NULL); + + switch (clist_row->cell[column].type) { - if (GPOINTER_TO_INT (list->data) >= row) - list->data = ((gchar*) list->data) + d; - list = list->next; + case GTK_CELL_TEXT: + requisition->width = + gdk_string_width (style->font, + GTK_CELL_TEXT (clist_row->cell[column])->text); + requisition->height = style->font->ascent + style->font->descent; + break; + case GTK_CELL_PIXTEXT: + gdk_window_get_size (GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap, + &width, &height); + requisition->width = width + + GTK_CELL_PIXTEXT (clist_row->cell[column])->spacing + + gdk_string_width (style->font, + GTK_CELL_TEXT (clist_row->cell[column])->text); + + requisition->height = MAX (style->font->ascent + style->font->descent, + height); + break; + case GTK_CELL_PIXMAP: + gdk_window_get_size (GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap, + &width, &height); + requisition->width = width; + requisition->height = height; + break; + default: + requisition->width = 0; + requisition->height = 0; + break; } + + requisition->width += clist_row->cell[column].horizontal; + requisition->height += clist_row->cell[column].vertical; } -void -gtk_clist_clear (GtkCList * clist) +/* PUBLIC INSERT/REMOVE ROW FUNCTIONS + * gtk_clist_prepend + * gtk_clist_append + * gtk_clist_insert + * gtk_clist_remove + * gtk_clist_clear + */ +gint +gtk_clist_prepend (GtkCList *clist, + gchar *text[]) { - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); - - GTK_CLIST_CLASS_FW (clist)->clear (clist); + g_return_val_if_fail (clist != NULL, -1); + g_return_val_if_fail (GTK_IS_CLIST (clist), -1); + g_return_val_if_fail (text != NULL, -1); + + return GTK_CLIST_CLASS_FW (clist)->insert_row (clist, 0, text); } -static void -real_clear (GtkCList * clist) +gint +gtk_clist_append (GtkCList *clist, + gchar *text[]) { - GList *list, *free_list; + g_return_val_if_fail (clist != NULL, -1); + g_return_val_if_fail (GTK_IS_CLIST (clist), -1); + g_return_val_if_fail (text != NULL, -1); - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); + return GTK_CLIST_CLASS_FW (clist)->insert_row (clist, clist->rows, text); +} - /* free up the selection list */ - g_list_free (clist->selection); - g_list_free (clist->undo_selection); - g_list_free (clist->undo_unselection); +gint +gtk_clist_insert (GtkCList *clist, + gint row, + gchar *text[]) +{ + g_return_val_if_fail (clist != NULL, -1); + g_return_val_if_fail (GTK_IS_CLIST (clist), -1); + g_return_val_if_fail (text != NULL, -1); - clist->selection = NULL; - clist->selection_end = NULL; - clist->undo_selection = NULL; - clist->undo_unselection = NULL; - clist->voffset = 0; - clist->focus_row = -1; - clist->anchor = -1; - clist->undo_anchor = -1; - clist->anchor_state = GTK_STATE_SELECTED; - clist->drag_pos = -1; + if (row < 0 || row > clist->rows) + row = clist->rows; - /* remove all the rows */ - free_list = clist->row_list; - clist->row_list = NULL; - clist->row_list_end = NULL; - clist->rows = 0; - for (list = free_list; list; list = list->next) - row_delete (clist, GTK_CLIST_ROW (list)); - g_list_free (free_list); + return GTK_CLIST_CLASS_FW (clist)->insert_row (clist, row, text); +} - /* zero-out the scrollbars */ - if (clist->vscrollbar) - { - GTK_RANGE (clist->vscrollbar)->adjustment->value = 0.0; - gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment), "changed"); - - if (!GTK_CLIST_FROZEN (clist)) - gtk_clist_thaw (clist); - } +void +gtk_clist_remove (GtkCList *clist, + gint row) +{ + GTK_CLIST_CLASS_FW (clist)->remove_row (clist, row); } -void -gtk_clist_swap_rows (GtkCList * clist, - gint row1, - gint row2) +void +gtk_clist_clear (GtkCList *clist) { - gint first, last; - GList *list, *link1, *link2; - gpointer swap; - g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); + + GTK_CLIST_CLASS_FW (clist)->clear (clist); +} - if (GTK_CLIST_AUTO_SORT (clist)) - return; +/* PRIVATE INSERT/REMOVE ROW FUNCTIONS + * real_insert_row + * real_remove_row + * real_clear + * sync_selection + */ +static gint +real_insert_row (GtkCList *clist, + gint row, + gchar *text[]) +{ + gint i; + GtkCListRow *clist_row; - if (row1 < 0 || row1 > (clist->rows - 1)) - return; + g_return_val_if_fail (clist != NULL, -1); + g_return_val_if_fail (GTK_IS_CLIST (clist), -1); + g_return_val_if_fail (text != NULL, -1); - if (row2 < 0 || row2 > (clist->rows - 1)) - return; + /* return if out of bounds */ + if (row < 0 || row > clist->rows) + return -1; - first = MIN (row1, row2); - last = MAX (row1, row2); + /* create the row */ + clist_row = row_new (clist); - link1 = g_list_nth (clist->row_list, first); - link2 = g_list_nth (link1, row2 - row1); + /* set the text in the row's columns */ + for (i = 0; i < clist->columns; i++) + if (text[i]) + GTK_CLIST_CLASS_FW (clist)->set_cell_contents + (clist, clist_row, i, GTK_CELL_TEXT, text[i], 0, NULL ,NULL); - swap = link1->data; - link1->data = link2->data; - link2->data = swap; - - list = clist->selection; - while (list) + if (!clist->rows) { - if (GPOINTER_TO_INT (list->data) == row1) - list->data = GINT_TO_POINTER (row2); - - if (GPOINTER_TO_INT (list->data) == row2) - list->data = GINT_TO_POINTER (row1); + clist->row_list = g_list_append (clist->row_list, clist_row); + clist->row_list_end = clist->row_list; + } + else + { + if (GTK_CLIST_AUTO_SORT (clist)) /* override insertion pos */ + { + GList *work; + + row = 0; + work = clist->row_list; + + if (clist->sort_type == GTK_SORT_ASCENDING) + { + while (row < clist->rows && + clist->compare (clist, clist_row, + GTK_CLIST_ROW (work)) > 0) + { + row++; + work = work->next; + } + } + else + { + while (row < clist->rows && + clist->compare (clist, clist_row, + GTK_CLIST_ROW (work)) < 0) + { + row++; + work = work->next; + } + } + } - list = list->next; + /* reset the row end pointer if we're inserting at the end of the list */ + if (row == clist->rows) + clist->row_list_end = (g_list_append (clist->row_list_end, + clist_row))->next; + else + clist->row_list = g_list_insert (clist->row_list, clist_row, row); } + clist->rows++; + + if (row < ROW_FROM_YPIXEL (clist, 0)) + clist->voffset -= (clist->row_height + CELL_SPACING); + + /* syncronize the selection list */ + sync_selection (clist, row, SYNC_INSERT); + + /* redraw the list if it isn't frozen */ if (!GTK_CLIST_FROZEN (clist)) { - if (gtk_clist_row_is_visible (clist, row1) != GTK_VISIBILITY_NONE) - GTK_CLIST_CLASS_FW (clist)->draw_row - (clist, NULL, row1, GTK_CLIST_ROW (link2)); + adjust_scrollbars (clist); - if (gtk_clist_row_is_visible (clist, row2) != GTK_VISIBILITY_NONE) - GTK_CLIST_CLASS_FW (clist)->draw_row - (clist, NULL, row2, GTK_CLIST_ROW (link1)); + if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE) + draw_rows (clist, NULL); + } + + return row; +} + +static void +real_remove_row (GtkCList *clist, + gint row) +{ + gint was_visible, was_selected; + GList *list; + GtkCListRow *clist_row; + + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); + + /* return if out of bounds */ + if (row < 0 || row > (clist->rows - 1)) + return; + + was_visible = (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE); + was_selected = 0; + + /* get the row we're going to delete */ + list = g_list_nth (clist->row_list, row); + clist_row = list->data; + + /* if we're removing a selected row, we have to make sure + * it's properly unselected, and then sync up the clist->selected + * list to reflect the deincrimented indexies of rows after the + * removal */ + if (clist_row->state == GTK_STATE_SELECTED) + { + switch (clist->selection_mode) + { + case GTK_SELECTION_SINGLE: + case GTK_SELECTION_MULTIPLE: + case GTK_SELECTION_EXTENDED: + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], + row, -1, NULL); + break; + case GTK_SELECTION_BROWSE: + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], + row - 1, -1, NULL); + break; + default: + break; + } + } + + /* reset the row end pointer if we're removing at the + * end of the list */ + if (row == clist->rows - 1) + clist->row_list_end = list->prev; + if (row >= clist->focus_row && clist->focus_row >=0) + clist->focus_row--; + + clist->row_list = g_list_remove (clist->row_list, clist_row); + clist->rows--; + + if (row < ROW_FROM_YPIXEL (clist, 0)) + clist->voffset += clist->row_height + CELL_SPACING; + + sync_selection (clist, row, SYNC_REMOVE); + + /* toast the row */ + row_delete (clist, clist_row); + + /* redraw the row if it isn't frozen */ + if (!GTK_CLIST_FROZEN (clist)) + { + adjust_scrollbars (clist); + + if (was_visible) + draw_rows (clist, NULL); + } +} + +static void +real_clear (GtkCList *clist) +{ + GList *list; + GList *free_list; + gint i; + + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); + + /* free up the selection list */ + g_list_free (clist->selection); + g_list_free (clist->undo_selection); + g_list_free (clist->undo_unselection); + + clist->selection = NULL; + clist->selection_end = NULL; + clist->undo_selection = NULL; + clist->undo_unselection = NULL; + clist->voffset = 0; + clist->focus_row = -1; + clist->anchor = -1; + clist->undo_anchor = -1; + clist->anchor_state = GTK_STATE_SELECTED; + clist->drag_pos = -1; + + /* remove all the rows */ + GTK_CLIST_SET_FLAG (clist, CLIST_AUTO_RESIZE_BLOCKED); + free_list = clist->row_list; + clist->row_list = NULL; + clist->row_list_end = NULL; + clist->rows = 0; + for (list = free_list; list; list = list->next) + row_delete (clist, GTK_CLIST_ROW (list)); + g_list_free (free_list); + GTK_CLIST_UNSET_FLAG (clist, CLIST_AUTO_RESIZE_BLOCKED); + for (i = 0; i < clist->columns; i++) + if (clist->column[i].auto_resize && clist->column[i].width > 0) + gtk_clist_set_column_width (clist, i, 0); + + /* zero-out the scrollbars */ + if (clist->vscrollbar) + { + GTK_RANGE (clist->vscrollbar)->adjustment->value = 0.0; + gtk_signal_emit_by_name + (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment), "changed"); + if (!GTK_CLIST_FROZEN (clist)) + gtk_clist_thaw (clist); } } +/* PUBLIC ROW FUNCTIONS + * gtk_clist_set_row_data + * gtk_clist_set_row_data_full + * gtk_clist_get_row_data + * gtk_clist_find_row_from_data + * gtk_clist_swap_rows + * gtk_clist_row_is_visible + * gtk_clist_set_foreground + * gtk_clist_set_background + */ void -gtk_clist_set_row_data (GtkCList * clist, - gint row, - gpointer data) +gtk_clist_set_row_data (GtkCList *clist, + gint row, + gpointer data) { gtk_clist_set_row_data_full (clist, row, data, NULL); } void -gtk_clist_set_row_data_full (GtkCList * clist, - gint row, - gpointer data, - GtkDestroyNotify destroy) +gtk_clist_set_row_data_full (GtkCList *clist, + gint row, + gpointer data, + GtkDestroyNotify destroy) { GtkCListRow *clist_row; @@ -2233,8 +2564,8 @@ gtk_clist_set_row_data_full (GtkCList * clist, } gpointer -gtk_clist_get_row_data (GtkCList * clist, - gint row) +gtk_clist_get_row_data (GtkCList *clist, + gint row) { GtkCListRow *clist_row; @@ -2249,8 +2580,8 @@ gtk_clist_get_row_data (GtkCList * clist, } gint -gtk_clist_find_row_from_data (GtkCList * clist, - gpointer data) +gtk_clist_find_row_from_data (GtkCList *clist, + gpointer data) { GList *list; gint n; @@ -2258,9 +2589,6 @@ gtk_clist_find_row_from_data (GtkCList * clist, g_return_val_if_fail (clist != NULL, -1); g_return_val_if_fail (GTK_IS_CLIST (clist), -1); - if (clist->rows < 1) - return -1; /* is this an optimization or just worthless? */ - for (n = 0, list = clist->row_list; list; n++, list = list->next) if (GTK_CLIST_ROW (list)->data == data) return n; @@ -2268,43 +2596,64 @@ gtk_clist_find_row_from_data (GtkCList * clist, return -1; } -void -gtk_clist_select_row (GtkCList * clist, - gint row, - gint column) +void +gtk_clist_swap_rows (GtkCList *clist, + gint row1, + gint row2) { + gint first, last; + GList *list, *link1, *link2; + gpointer swap; + g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); - if (row < 0 || row >= clist->rows) + if (GTK_CLIST_AUTO_SORT (clist)) return; - if (column < -1 || column >= clist->columns) + if (row1 < 0 || row1 > (clist->rows - 1)) return; - select_row (clist, row, column, NULL); -} + if (row2 < 0 || row2 > (clist->rows - 1)) + return; -void -gtk_clist_unselect_row (GtkCList * clist, - gint row, - gint column) -{ - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); + first = MIN (row1, row2); + last = MAX (row1, row2); - if (row < 0 || row >= clist->rows) - return; + link1 = g_list_nth (clist->row_list, first); + link2 = g_list_nth (link1, row2 - row1); - if (column < -1 || column >= clist->columns) - return; + swap = link1->data; + link1->data = link2->data; + link2->data = swap; + + list = clist->selection; + while (list) + { + if (GPOINTER_TO_INT (list->data) == row1) + list->data = GINT_TO_POINTER (row2); + + if (GPOINTER_TO_INT (list->data) == row2) + list->data = GINT_TO_POINTER (row1); + + list = list->next; + } + + if (!GTK_CLIST_FROZEN (clist)) + { + if (gtk_clist_row_is_visible (clist, row1) != GTK_VISIBILITY_NONE) + GTK_CLIST_CLASS_FW (clist)->draw_row + (clist, NULL, row1, GTK_CLIST_ROW (link2)); - unselect_row (clist, row, column, NULL); + if (gtk_clist_row_is_visible (clist, row2) != GTK_VISIBILITY_NONE) + GTK_CLIST_CLASS_FW (clist)->draw_row + (clist, NULL, row2, GTK_CLIST_ROW (link1)); + } } GtkVisibility -gtk_clist_row_is_visible (GtkCList * clist, - gint row) +gtk_clist_row_is_visible (GtkCList *clist, + gint row) { gint top; @@ -2332,3607 +2681,3756 @@ gtk_clist_row_is_visible (GtkCList * clist, return GTK_VISIBILITY_FULL; } -#if 0 -static GtkAdjustment* -gtk_clist_get_vadjustment (GtkCList * clist) -{ - g_return_val_if_fail (clist != NULL, NULL); - g_return_val_if_fail (GTK_IS_CLIST (clist), NULL); - - return gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar)); -} - -static GtkAdjustment* -gtk_clist_get_hadjustment (GtkCList * clist) -{ - g_return_val_if_fail (clist != NULL, NULL); - g_return_val_if_fail (GTK_IS_CLIST (clist), NULL); - - return gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar)); -} -#endif - void -gtk_clist_set_policy (GtkCList * clist, - GtkPolicyType vscrollbar_policy, - GtkPolicyType hscrollbar_policy) +gtk_clist_set_foreground (GtkCList *clist, + gint row, + GdkColor *color) { + GtkCListRow *clist_row; + g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); - if (clist->vscrollbar_policy != vscrollbar_policy) - { - clist->vscrollbar_policy = vscrollbar_policy; + if (row < 0 || row >= clist->rows) + return; - if (GTK_WIDGET (clist)->parent) - gtk_widget_queue_resize (GTK_WIDGET (clist)); - } + clist_row = (g_list_nth (clist->row_list, row))->data; - if (clist->hscrollbar_policy != hscrollbar_policy) + if (color) { - clist->hscrollbar_policy = hscrollbar_policy; - - if (GTK_WIDGET (clist)->parent) - gtk_widget_queue_resize (GTK_WIDGET (clist)); + clist_row->foreground = *color; + clist_row->fg_set = TRUE; + if (GTK_WIDGET_REALIZED (clist)) + gdk_color_alloc (gtk_widget_get_colormap (GTK_WIDGET (clist)), + &clist_row->foreground); } + else + clist_row->fg_set = FALSE; + + if (!GTK_CLIST_FROZEN (clist) + && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)) + GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row); } void -gtk_clist_undo_selection (GtkCList *clist) +gtk_clist_set_background (GtkCList *clist, + gint row, + GdkColor *color) { + GtkCListRow *clist_row; + g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); - if (clist->selection_mode == GTK_SELECTION_EXTENDED && - (clist->undo_selection || clist->undo_unselection)) - gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNDO_SELECTION]); + if (row < 0 || row >= clist->rows) + return; + + clist_row = (g_list_nth (clist->row_list, row))->data; + + if (color) + { + clist_row->background = *color; + clist_row->bg_set = TRUE; + if (GTK_WIDGET_REALIZED (clist)) + gdk_color_alloc (gtk_widget_get_colormap (GTK_WIDGET (clist)), + &clist_row->background); + } + else + clist_row->bg_set = FALSE; + + if (!GTK_CLIST_FROZEN (clist) + && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)) + GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row); } -static void -real_undo_selection (GtkCList *clist) +/* PUBLIC ROW/CELL STYLE FUNCTIONS + * gtk_clist_set_cell_style + * gtk_clist_get_cell_style + * gtk_clist_set_row_style + * gtk_clist_get_row_style + */ +void +gtk_clist_set_cell_style (GtkCList *clist, + gint row, + gint column, + GtkStyle *style) { - GList *work; + GtkRequisition requisition; + GtkCListRow *clist_row; g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); - if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) || - clist->selection_mode != GTK_SELECTION_EXTENDED) + if (row < 0 || row >= clist->rows) + return; + if (column < 0 || column >= clist->columns) return; - if (clist->anchor >= 0) - GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL); + clist_row = (g_list_nth (clist->row_list, row))->data; - if (!(clist->undo_selection || clist->undo_unselection)) + if (clist_row->cell[column].style == style) + return; + + if (clist->column[column].auto_resize && + !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist)) + GTK_CLIST_CLASS_FW (clist)->cell_size_request (clist, clist_row, + column, &requisition); + + if (clist_row->cell[column].style) { - gtk_clist_unselect_all (clist); - return; + if (GTK_WIDGET_REALIZED (clist)) + gtk_style_detach (clist_row->cell[column].style); + gtk_style_unref (clist_row->cell[column].style); } - for (work = clist->undo_selection; work; work = work->next) - gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], - GPOINTER_TO_INT (work->data), -1, NULL); + clist_row->cell[column].style = style; - for (work = clist->undo_unselection; work; work = work->next) - gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], - GPOINTER_TO_INT (work->data), -1, NULL); + if (clist_row->cell[column].style) + { + gtk_style_ref (clist_row->cell[column].style); + + if (GTK_WIDGET_REALIZED (clist)) + clist_row->cell[column].style = + gtk_style_attach (clist_row->cell[column].style, + clist->clist_window); + } - if (GTK_WIDGET_HAS_FOCUS (clist) && clist->focus_row != clist->undo_anchor) + column_auto_resize (clist, clist_row, column, requisition.width); + + /* redraw the list if it's not frozen */ + if (!GTK_CLIST_FROZEN (clist)) { - gtk_clist_draw_focus (GTK_WIDGET (clist)); - clist->focus_row = clist->undo_anchor; - gtk_clist_draw_focus (GTK_WIDGET (clist)); + if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE) + GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row); } - else - clist->focus_row = clist->undo_anchor; - - clist->undo_anchor = -1; - - g_list_free (clist->undo_selection); - g_list_free (clist->undo_unselection); - clist->undo_selection = NULL; - clist->undo_unselection = NULL; +} - if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height > - clist->clist_window_height) - gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0); - else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0) - gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0); +GtkStyle * +gtk_clist_get_cell_style (GtkCList *clist, + gint row, + gint column) +{ + GtkCListRow *clist_row; + + g_return_val_if_fail (clist != NULL, NULL); + g_return_val_if_fail (GTK_IS_CLIST (clist), NULL); + + if (row < 0 || row >= clist->rows || column < 0 || column >= clist->columns) + return NULL; + + clist_row = (g_list_nth (clist->row_list, row))->data; + + return clist_row->cell[column].style; } -/* - * GTKOBJECT - * gtk_clist_destroy - * gtk_clist_finalize - */ -static void -gtk_clist_destroy (GtkObject * object) +void +gtk_clist_set_row_style (GtkCList *clist, + gint row, + GtkStyle *style) { + GtkRequisition requisition; + GtkCListRow *clist_row; + gint *old_width; gint i; - GtkCList *clist; - g_return_if_fail (object != NULL); - g_return_if_fail (GTK_IS_CLIST (object)); + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); - clist = GTK_CLIST (object); + if (row < 0 || row >= clist->rows) + return; - /* freeze the list */ - GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN); + clist_row = (g_list_nth (clist->row_list, row))->data; - /* get rid of all the rows */ - gtk_clist_clear (clist); + if (clist_row->style == style) + return; - /* Since we don't have a _remove method, unparent the children - * instead of destroying them so the focus will be unset properly. - * (For other containers, the _remove method takes care of the - * unparent) The destroy will happen when the refcount drops - * to zero. - */ + old_width = g_new (gint, clist->columns); - /* destroy the scrollbars */ - if (clist->vscrollbar) + if (!GTK_CLIST_AUTO_RESIZE_BLOCKED (clist)) { - gtk_widget_unparent (clist->vscrollbar); - clist->vscrollbar = NULL; + for (i = 0; i < clist->columns; i++) + if (clist->column[i].auto_resize) + { + GTK_CLIST_CLASS_FW (clist)->cell_size_request (clist, clist_row, + i, &requisition); + old_width[i] = requisition.width; + } } - if (clist->hscrollbar) + + if (clist_row->style) { - gtk_widget_unparent (clist->hscrollbar); - clist->hscrollbar = NULL; + if (GTK_WIDGET_REALIZED (clist)) + gtk_style_detach (clist_row->style); + gtk_style_unref (clist_row->style); } - if (clist->htimer) + clist_row->style = style; + + if (clist_row->style) { - gtk_timeout_remove (clist->htimer); - clist->htimer = 0; + gtk_style_ref (clist_row->style); + + if (GTK_WIDGET_REALIZED (clist)) + clist_row->style = gtk_style_attach (clist_row->style, + clist->clist_window); } - if (clist->vtimer) + + if (GTK_CLIST_AUTO_RESIZE_BLOCKED (clist)) { - gtk_timeout_remove (clist->vtimer); - clist->vtimer = 0; + for (i = 0; i < clist->columns; i++) + if (clist->column[i].auto_resize) + column_auto_resize (clist, clist_row, i, old_width[i]); } - /* destroy the column buttons */ - for (i = 0; i < clist->columns; i++) - if (clist->column[i].button) - { - gtk_widget_unparent (clist->column[i].button); - clist->column[i].button = NULL; - } + g_free (old_width); - if (GTK_OBJECT_CLASS (parent_class)->destroy) - (*GTK_OBJECT_CLASS (parent_class)->destroy) (object); + /* redraw the list if it's not frozen */ + if (!GTK_CLIST_FROZEN (clist)) + { + if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE) + GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row); + } } -static void -gtk_clist_finalize (GtkObject * object) +GtkStyle * +gtk_clist_get_row_style (GtkCList *clist, + gint row) { - GtkCList *clist; - - g_return_if_fail (object != NULL); - g_return_if_fail (GTK_IS_CLIST (object)); + GtkCListRow *clist_row; - clist = GTK_CLIST (object); + g_return_val_if_fail (clist != NULL, NULL); + g_return_val_if_fail (GTK_IS_CLIST (clist), NULL); - columns_delete (clist); + if (row < 0 || row >= clist->rows) + return NULL; - g_mem_chunk_destroy (clist->cell_mem_chunk); - g_mem_chunk_destroy (clist->row_mem_chunk); + clist_row = (g_list_nth (clist->row_list, row))->data; - if (GTK_OBJECT_CLASS (parent_class)->finalize) - (*GTK_OBJECT_CLASS (parent_class)->finalize) (object); + return clist_row->style; } -/* - * GTKWIDGET - * gtk_clist_realize - * gtk_clist_unrealize - * gtk_clist_map - * gtk_clist_unmap - * gtk_clist_draw - * gtk_clist_expose - * gtk_clist_button_press - * gtk_clist_button_release - * gtk_clist_motion - * gtk_clist_size_request - * gtk_clist_size_allocate +/* PUBLIC SELECTION FUNCTIONS + * gtk_clist_set_selectable + * gtk_clist_get_selectable + * gtk_clist_select_row + * gtk_clist_unselect_row + * gtk_clist_select_all + * gtk_clist_unselect_all + * gtk_clist_undo_selection */ -static void -gtk_clist_realize (GtkWidget * widget) +void +gtk_clist_set_selectable (GtkCList *clist, + gint row, + gboolean selectable) { - GtkCList *clist; - GdkWindowAttr attributes; - GdkGCValues values; GtkCListRow *clist_row; - GList *list; - gint attributes_mask; - gint border_width; - gint i; - gint j; - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_CLIST (widget)); + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); - clist = GTK_CLIST (widget); + if (row < 0 || row >= clist->rows) + return; - GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + clist_row = (g_list_nth (clist->row_list, row))->data; - add_style_data (clist); + if (selectable == clist_row->selectable) + return; - border_width = GTK_CONTAINER (widget)->border_width; - - attributes.window_type = GDK_WINDOW_CHILD; - attributes.x = widget->allocation.x + border_width; - attributes.y = widget->allocation.y + border_width; - attributes.width = widget->allocation.width - border_width * 2; - attributes.height = widget->allocation.height - border_width * 2; - attributes.wclass = GDK_INPUT_OUTPUT; - attributes.visual = gtk_widget_get_visual (widget); - attributes.colormap = gtk_widget_get_colormap (widget); - attributes.event_mask = gtk_widget_get_events (widget); - attributes.event_mask |= (GDK_EXPOSURE_MASK | - GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | - GDK_KEY_PRESS_MASK | - GDK_KEY_RELEASE_MASK); - attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + clist_row->selectable = selectable; - /* main window */ - widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), - &attributes, attributes_mask); - gdk_window_set_user_data (widget->window, clist); + if (!selectable && clist_row->state == GTK_STATE_SELECTED) + { + if (clist->anchor >= 0 && + clist->selection_mode == GTK_SELECTION_EXTENDED) + { + if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_FOCUS (clist))) + { + GTK_CLIST_UNSET_FLAG (clist, CLIST_DRAG_SELECTION); + gtk_grab_remove (GTK_WIDGET (clist)); + gdk_pointer_ungrab (GDK_CURRENT_TIME); + if (clist->htimer) + { + gtk_timeout_remove (clist->htimer); + clist->htimer = 0; + } + if (clist->vtimer) + { + gtk_timeout_remove (clist->vtimer); + clist->vtimer = 0; + } + } + GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL); + } + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], + row, -1, NULL); + } +} - widget->style = gtk_style_attach (widget->style, widget->window); +gboolean +gtk_clist_get_selectable (GtkCList *clist, + gint row) +{ + g_return_val_if_fail (clist != NULL, FALSE); + g_return_val_if_fail (GTK_IS_CLIST (clist), FALSE); - gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); + if (row < 0 || row >= clist->rows) + return FALSE; - /* column-title window */ + return GTK_CLIST_ROW (g_list_nth (clist->row_list, row))->selectable; +} - attributes.x = clist->column_title_area.x; - attributes.y = clist->column_title_area.y; - attributes.width = clist->column_title_area.width; - attributes.height = clist->column_title_area.height; - - clist->title_window = gdk_window_new (widget->window, &attributes, - attributes_mask); - gdk_window_set_user_data (clist->title_window, clist); +void +gtk_clist_select_row (GtkCList *clist, + gint row, + gint column) +{ + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); - gtk_style_set_background (widget->style, clist->title_window, - GTK_STATE_SELECTED); - gdk_window_show (clist->title_window); + if (row < 0 || row >= clist->rows) + return; + if (column < -1 || column >= clist->columns) + return; - /* set things up so column buttons are drawn in title window */ - for (i = 0; i < clist->columns; i++) - if (clist->column[i].button) - gtk_widget_set_parent_window (clist->column[i].button, - clist->title_window); + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], + row, column, NULL); +} - /* clist-window */ - attributes.x = (clist->internal_allocation.x + - widget->style->klass->xthickness); - attributes.y = (clist->internal_allocation.y + - widget->style->klass->ythickness + - clist->column_title_area.height); - attributes.width = clist->clist_window_width; - attributes.height = clist->clist_window_height; - - clist->clist_window = gdk_window_new (widget->window, &attributes, - attributes_mask); - gdk_window_set_user_data (clist->clist_window, clist); +void +gtk_clist_unselect_row (GtkCList *clist, + gint row, + gint column) +{ + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); - gdk_window_set_background (clist->clist_window, - &widget->style->bg[GTK_STATE_PRELIGHT]); - gdk_window_show (clist->clist_window); - gdk_window_get_size (clist->clist_window, &clist->clist_window_width, - &clist->clist_window_height); + if (row < 0 || row >= clist->rows) + return; + if (column < -1 || column >= clist->columns) + return; - /* create resize windows */ - attributes.wclass = GDK_INPUT_ONLY; - attributes.event_mask = (GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | - GDK_POINTER_MOTION_MASK | - GDK_POINTER_MOTION_HINT_MASK | - GDK_KEY_PRESS_MASK); - attributes_mask = GDK_WA_CURSOR; - attributes.cursor = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW); - clist->cursor_drag = attributes.cursor; + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], + row, column, NULL); +} - attributes.x = LIST_WIDTH (clist) + 1; - attributes.y = 0; - attributes.width = 0; - attributes.height = 0; +void +gtk_clist_select_all (GtkCList *clist) +{ + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); - for (i = 0; i < clist->columns; i++) - { - clist->column[i].window = gdk_window_new (clist->title_window, - &attributes, attributes_mask); - gdk_window_set_user_data (clist->column[i].window, clist); - } + GTK_CLIST_CLASS_FW (clist)->select_all (clist); +} - /* This is slightly less efficient than creating them with the - * right size to begin with, but easier - */ - size_allocate_title_buttons (clist); +void +gtk_clist_unselect_all (GtkCList *clist) +{ + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); - /* GCs */ - clist->fg_gc = gdk_gc_new (widget->window); - clist->bg_gc = gdk_gc_new (widget->window); - - /* We'll use this gc to do scrolling as well */ - gdk_gc_set_exposures (clist->fg_gc, TRUE); + GTK_CLIST_CLASS_FW (clist)->unselect_all (clist); +} - values.foreground = widget->style->white; - values.function = GDK_XOR; - values.subwindow_mode = GDK_INCLUDE_INFERIORS; - clist->xor_gc = gdk_gc_new_with_values (widget->window, - &values, - GDK_GC_FOREGROUND | - GDK_GC_FUNCTION | - GDK_GC_SUBWINDOW); +void +gtk_clist_undo_selection (GtkCList *clist) +{ + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); - /* attach optional row/cell styles, allocate foreground/background colors */ - list = clist->row_list; - for (i = 0; i < clist->rows; i++) - { - clist_row = list->data; - list = list->next; + if (clist->selection_mode == GTK_SELECTION_EXTENDED && + (clist->undo_selection || clist->undo_unselection)) + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNDO_SELECTION]); +} - if (clist_row->style) - clist_row->style = gtk_style_attach (clist_row->style, - clist->clist_window); +/* PRIVATE SELECTION FUNCTIONS + * selection_find + * toggle_row + * fake_toggle_row + * toggle_focus_row + * toggle_add_mode + * real_select_row + * real_unselect_row + * real_select_all + * real_unselect_all + * fake_unselect_all + * real_undo_selection + * set_anchor + * resync_selection + * update_extended_selection + * start_selection + * end_selection + * extend_selection + * sync_selection + */ +static GList * +selection_find (GtkCList *clist, + gint row_number, + GList *row_list_element) +{ + return g_list_find (clist->selection, GINT_TO_POINTER (row_number)); +} - if (clist_row->fg_set || clist_row->bg_set) - { - GdkColormap *colormap; +static void +toggle_row (GtkCList *clist, + gint row, + gint column, + GdkEvent *event) +{ + GtkCListRow *clist_row; - colormap = gtk_widget_get_colormap (widget); - if (clist_row->fg_set) - gdk_color_alloc (colormap, &clist_row->foreground); - if (clist_row->bg_set) - gdk_color_alloc (colormap, &clist_row->background); + switch (clist->selection_mode) + { + case GTK_SELECTION_EXTENDED: + case GTK_SELECTION_MULTIPLE: + case GTK_SELECTION_SINGLE: + clist_row = g_list_nth (clist->row_list, row)->data; + if (clist_row->state == GTK_STATE_SELECTED) + { + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], + row, column, event); + return; } - - for (j = 0; j < clist->columns; j++) - if (clist_row->cell[j].style) - clist_row->cell[j].style = - gtk_style_attach (clist_row->cell[j].style, clist->clist_window); + case GTK_SELECTION_BROWSE: + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], + row, column, event); + break; } } static void -gtk_clist_unrealize (GtkWidget * widget) +fake_toggle_row (GtkCList *clist, + gint row) { - gint i; - GtkCList *clist; - - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_CLIST (widget)); + GList *work; - clist = GTK_CLIST (widget); + if (!(work = g_list_nth (clist->row_list, row))|| + !GTK_CLIST_ROW (work)->selectable) + return; + + if (GTK_CLIST_ROW (work)->state == GTK_STATE_NORMAL) + clist->anchor_state = GTK_CLIST_ROW (work)->state = GTK_STATE_SELECTED; + else + clist->anchor_state = GTK_CLIST_ROW (work)->state = GTK_STATE_NORMAL; + + if (!GTK_CLIST_FROZEN (clist) && + gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE) + GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, + GTK_CLIST_ROW (work)); +} - GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN); +static void +toggle_focus_row (GtkCList *clist) +{ + g_return_if_fail (clist != 0); + g_return_if_fail (GTK_IS_CLIST (clist)); - /* detach optional row/cell styles */ + if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) || + clist->focus_row < 0 || clist->focus_row >= clist->rows) + return; - if (GTK_WIDGET_REALIZED (widget)) + switch (clist->selection_mode) { - GtkCListRow *clist_row; - GList *list; - gint j; + case GTK_SELECTION_SINGLE: + case GTK_SELECTION_MULTIPLE: + toggle_row (clist, clist->focus_row, 0, NULL); + break; + case GTK_SELECTION_EXTENDED: + g_list_free (clist->undo_selection); + g_list_free (clist->undo_unselection); + clist->undo_selection = NULL; + clist->undo_unselection = NULL; - list = clist->row_list; - for (i = 0; i < clist->rows; i++) - { - clist_row = list->data; - list = list->next; + clist->anchor = clist->focus_row; + clist->drag_pos = clist->focus_row; + clist->undo_anchor = clist->focus_row; + + if (GTK_CLIST_ADD_MODE (clist)) + fake_toggle_row (clist, clist->focus_row); + else + GTK_CLIST_CLASS_FW (clist)->fake_unselect_all (clist,clist->focus_row); - if (clist_row->style) - gtk_style_detach (clist_row->style); - for (j = 0; j < clist->columns; j++) - if (clist_row->cell[j].style) - gtk_style_detach (clist_row->cell[j].style); - } + GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL); + break; + default: + break; } - - gdk_cursor_destroy (clist->cursor_drag); - gdk_gc_destroy (clist->xor_gc); - gdk_gc_destroy (clist->fg_gc); - gdk_gc_destroy (clist->bg_gc); - - for (i = 0; i < clist->columns; i++) - if (clist->column[i].window) - { - gdk_window_set_user_data (clist->column[i].window, NULL); - gdk_window_destroy (clist->column[i].window); - clist->column[i].window = NULL; - } - - gdk_window_set_user_data (clist->clist_window, NULL); - gdk_window_destroy (clist->clist_window); - clist->clist_window = NULL; - - gdk_window_set_user_data (clist->title_window, NULL); - gdk_window_destroy (clist->title_window); - clist->title_window = NULL; - - clist->cursor_drag = NULL; - clist->xor_gc = NULL; - clist->fg_gc = NULL; - clist->bg_gc = NULL; - - if (GTK_WIDGET_CLASS (parent_class)->unrealize) - (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget); } static void -gtk_clist_map (GtkWidget * widget) +toggle_add_mode (GtkCList *clist) { - gint i; - GtkCList *clist; - - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_CLIST (widget)); - - clist = GTK_CLIST (widget); + g_return_if_fail (clist != 0); + g_return_if_fail (GTK_IS_CLIST (clist)); + + if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) || + clist->selection_mode != GTK_SELECTION_EXTENDED) + return; - if (!GTK_WIDGET_MAPPED (widget)) + gtk_clist_draw_focus (GTK_WIDGET (clist)); + if (!GTK_CLIST_ADD_MODE (clist)) { - GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); - - gdk_window_show (widget->window); - gdk_window_show (clist->title_window); - gdk_window_show (clist->clist_window); - - /* map column buttons */ - for (i = 0; i < clist->columns; i++) - if (clist->column[i].button && - GTK_WIDGET_VISIBLE (clist->column[i].button) && - !GTK_WIDGET_MAPPED (clist->column[i].button)) - gtk_widget_map (clist->column[i].button); - - /* map resize windows AFTER column buttons (above) */ - for (i = 0; i < clist->columns; i++) - if (clist->column[i].window && clist->column[i].button) - gdk_window_show (clist->column[i].window); - - /* map vscrollbars */ - if (GTK_WIDGET_VISIBLE (clist->vscrollbar) && - !GTK_WIDGET_MAPPED (clist->vscrollbar)) - gtk_widget_map (clist->vscrollbar); - - if (GTK_WIDGET_VISIBLE (clist->hscrollbar) && - !GTK_WIDGET_MAPPED (clist->hscrollbar)) - gtk_widget_map (clist->hscrollbar); - - /* unfreeze the list */ - GTK_CLIST_UNSET_FLAG (clist, CLIST_FROZEN); + GTK_CLIST_SET_FLAG (clist, CLIST_ADD_MODE); + gdk_gc_set_line_attributes (clist->xor_gc, 1, + GDK_LINE_ON_OFF_DASH, 0, 0); + gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2); } + else + { + GTK_CLIST_UNSET_FLAG (clist, CLIST_ADD_MODE); + gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_SOLID, 0, 0); + clist->anchor_state = GTK_STATE_SELECTED; + } + gtk_clist_draw_focus (GTK_WIDGET (clist)); } static void -gtk_clist_unmap (GtkWidget * widget) +real_select_row (GtkCList *clist, + gint row, + gint column, + GdkEvent *event) { - gint i; - GtkCList *clist; + GtkCListRow *clist_row; + GList *list; + gint sel_row; + gboolean row_selected; - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_CLIST (widget)); + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); - clist = GTK_CLIST (widget); + if (row < 0 || row > (clist->rows - 1)) + return; - if (GTK_WIDGET_MAPPED (widget)) + switch (clist->selection_mode) { - GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); + case GTK_SELECTION_SINGLE: + case GTK_SELECTION_BROWSE: - for (i = 0; i < clist->columns; i++) - if (clist->column[i].window) - gdk_window_hide (clist->column[i].window); + row_selected = FALSE; + list = clist->selection; - gdk_window_hide (clist->clist_window); - gdk_window_hide (clist->title_window); - gdk_window_hide (widget->window); + while (list) + { + sel_row = GPOINTER_TO_INT (list->data); + list = list->next; - /* unmap scrollbars */ - if (GTK_WIDGET_MAPPED (clist->vscrollbar)) - gtk_widget_unmap (clist->vscrollbar); + if (row == sel_row) + row_selected = TRUE; + else + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], + sel_row, column, event); + } - if (GTK_WIDGET_MAPPED (clist->hscrollbar)) - gtk_widget_unmap (clist->hscrollbar); + if (row_selected) + return; + + default: + break; + } - /* unmap column buttons */ - for (i = 0; i < clist->columns; i++) - if (clist->column[i].button && - GTK_WIDGET_MAPPED (clist->column[i].button)) - gtk_widget_unmap (clist->column[i].button); + clist_row = (g_list_nth (clist->row_list, row))->data; - /* freeze the list */ - GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN); + if (clist_row->state != GTK_STATE_NORMAL || !clist_row->selectable) + return; + + clist_row->state = GTK_STATE_SELECTED; + if (!clist->selection) + { + clist->selection = g_list_append (clist->selection, + GINT_TO_POINTER (row)); + clist->selection_end = clist->selection; } + else + clist->selection_end = + g_list_append (clist->selection_end, GINT_TO_POINTER (row))->next; + + if (!GTK_CLIST_FROZEN (clist) + && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)) + GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row); } static void -gtk_clist_draw (GtkWidget * widget, - GdkRectangle * area) +real_unselect_row (GtkCList *clist, + gint row, + gint column, + GdkEvent *event) { - GtkCList *clist; - gint border_width; - GdkRectangle child_area; - int i; - - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_CLIST (widget)); - g_return_if_fail (area != NULL); + GtkCListRow *clist_row; - if (GTK_WIDGET_DRAWABLE (widget)) - { - clist = GTK_CLIST (widget); - border_width = GTK_CONTAINER (widget)->border_width; + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); - gdk_window_clear_area (widget->window, - area->x - border_width, - area->y - border_width, - area->width, area->height); + if (row < 0 || row > (clist->rows - 1)) + return; - /* draw list shadow/border */ - gtk_draw_shadow (widget->style, widget->window, - GTK_STATE_NORMAL, clist->shadow_type, - 0, 0, - clist->clist_window_width + (2 * widget->style->klass->xthickness), - clist->clist_window_height + (2 * widget->style->klass->ythickness) + - clist->column_title_area.height); + clist_row = (g_list_nth (clist->row_list, row))->data; - gdk_window_clear_area (clist->clist_window, - 0, 0, -1, -1); + if (clist_row->state == GTK_STATE_SELECTED) + { + clist_row->state = GTK_STATE_NORMAL; - draw_rows (clist, NULL); + if (clist->selection_end && + clist->selection_end->data == GINT_TO_POINTER (row)) + clist->selection_end = clist->selection_end->prev; - for (i = 0; i < clist->columns; i++) - { - if (!clist->column[i].visible) - continue; - if (gtk_widget_intersect (clist->column[i].button, area, &child_area)) - gtk_widget_draw (clist->column[i].button, &child_area); - } + clist->selection = g_list_remove (clist->selection, + GINT_TO_POINTER (row)); + + if (!GTK_CLIST_FROZEN (clist) + && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)) + GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row); } } -static gint -gtk_clist_expose (GtkWidget * widget, - GdkEventExpose * event) +static void +real_select_all (GtkCList *clist) { - GtkCList *clist; + GList *list; + gint i; + + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); - g_return_val_if_fail (widget != NULL, FALSE); - g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); + if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) + return; - if (GTK_WIDGET_DRAWABLE (widget)) + switch (clist->selection_mode) { - clist = GTK_CLIST (widget); + case GTK_SELECTION_SINGLE: + case GTK_SELECTION_BROWSE: + return; - /* draw border */ - if (event->window == widget->window) - gtk_draw_shadow (widget->style, widget->window, - GTK_STATE_NORMAL, clist->shadow_type, - 0, 0, - clist->clist_window_width + (2 * widget->style->klass->xthickness), - clist->clist_window_height + (2 * widget->style->klass->ythickness) + - clist->column_title_area.height); + case GTK_SELECTION_EXTENDED: + g_list_free (clist->undo_selection); + g_list_free (clist->undo_unselection); + clist->undo_selection = NULL; + clist->undo_unselection = NULL; + + if (clist->rows && + ((GtkCListRow *) (clist->row_list->data))->state != + GTK_STATE_SELECTED) + fake_toggle_row (clist, 0); - /* exposure events on the list */ - if (event->window == clist->clist_window) - draw_rows (clist, &event->area); - } + clist->anchor_state = GTK_STATE_SELECTED; + clist->anchor = 0; + clist->drag_pos = 0; + clist->undo_anchor = clist->focus_row; + update_extended_selection (clist, clist->rows); + GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL); + return; - return FALSE; + case GTK_SELECTION_MULTIPLE: + for (i = 0, list = clist->row_list; list; i++, list = list->next) + { + if (((GtkCListRow *)(list->data))->state == GTK_STATE_NORMAL) + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], + i, -1, NULL); + } + return; + } } -static gint -gtk_clist_button_press (GtkWidget * widget, - GdkEventButton * event) +static void +real_unselect_all (GtkCList *clist) { + GList *list; gint i; - GtkCList *clist; - gint x; - gint y; - gint row; - gint column; - - g_return_val_if_fail (widget != NULL, FALSE); - g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); + + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); - clist = GTK_CLIST (widget); + if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) + return; - /* we don't handle button 2 and 3 */ - if (event->button != 1) - return FALSE; - - /* selections on the list */ - if (event->window == clist->clist_window) + switch (clist->selection_mode) { - x = event->x; - y = event->y; - - if (get_selection_info (clist, x, y, &row, &column)) + case GTK_SELECTION_BROWSE: + if (clist->focus_row >= 0) { - gint old_row = clist->focus_row; + gtk_signal_emit (GTK_OBJECT (clist), + clist_signals[SELECT_ROW], + clist->focus_row, -1, NULL); + return; + } + break; + case GTK_SELECTION_EXTENDED: + g_list_free (clist->undo_selection); + g_list_free (clist->undo_unselection); + clist->undo_selection = NULL; + clist->undo_unselection = NULL; - if (clist->focus_row == -1) - old_row = row; + clist->anchor = -1; + clist->drag_pos = -1; + clist->undo_anchor = clist->focus_row; + break; + default: + break; + } - if (event->type == GDK_BUTTON_PRESS) - { - GTK_CLIST_SET_FLAG (clist, CLIST_DRAG_SELECTION); - gdk_pointer_grab (clist->clist_window, FALSE, - GDK_POINTER_MOTION_HINT_MASK | - GDK_BUTTON1_MOTION_MASK | - GDK_BUTTON_RELEASE_MASK, - NULL, NULL, event->time); - gtk_grab_add (widget); - } - else if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (widget)) - { - GTK_CLIST_UNSET_FLAG (clist, CLIST_DRAG_SELECTION); - gtk_grab_remove (widget); - gdk_pointer_ungrab (event->time); - } + list = clist->selection; + while (list) + { + i = GPOINTER_TO_INT (list->data); + list = list->next; + gtk_signal_emit (GTK_OBJECT (clist), + clist_signals[UNSELECT_ROW], i, -1, NULL); + } +} - if (GTK_CLIST_ADD_MODE (clist)) - { - GTK_CLIST_UNSET_FLAG (clist, CLIST_ADD_MODE); - if (GTK_WIDGET_HAS_FOCUS (widget)) - { - gtk_clist_draw_focus (widget); - gdk_gc_set_line_attributes (clist->xor_gc, 1, - GDK_LINE_SOLID, 0, 0); - clist->focus_row = row; - gtk_clist_draw_focus (widget); - } - else - { - gdk_gc_set_line_attributes (clist->xor_gc, 1, - GDK_LINE_SOLID, 0, 0); - clist->focus_row = row; - } - } - else if (row != clist->focus_row) - { - if (GTK_WIDGET_HAS_FOCUS (widget)) - { - gtk_clist_draw_focus (widget); - clist->focus_row = row; - gtk_clist_draw_focus (widget); - } - else - clist->focus_row = row; - } +static void +fake_unselect_all (GtkCList *clist, + gint row) +{ + GList *list; + GList *work; + gint i; - if (!GTK_WIDGET_HAS_FOCUS (widget)) - gtk_widget_grab_focus (widget); + if (row >= 0 && (work = g_list_nth (clist->row_list, row))) + { + if (GTK_CLIST_ROW (work)->state == GTK_STATE_NORMAL && + GTK_CLIST_ROW (work)->selectable) + { + GTK_CLIST_ROW (work)->state = GTK_STATE_SELECTED; + + if (!GTK_CLIST_FROZEN (clist) && + gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE) + GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, + GTK_CLIST_ROW (work)); + } + } - switch (clist->selection_mode) - { - case GTK_SELECTION_SINGLE: - case GTK_SELECTION_MULTIPLE: - if (event->type != GDK_BUTTON_PRESS) - select_row (clist, row, column, (GdkEvent *) event); - else - clist->anchor = row; - break; + clist->undo_selection = clist->selection; + clist->selection = NULL; + clist->selection_end = NULL; + + for (list = clist->undo_selection; list; list = list->next) + { + if ((i = GPOINTER_TO_INT (list->data)) == row || + !(work = g_list_nth (clist->row_list, i))) + continue; - case GTK_SELECTION_BROWSE: - select_row (clist, row, column, (GdkEvent *) event); - break; + GTK_CLIST_ROW (work)->state = GTK_STATE_NORMAL; + if (!GTK_CLIST_FROZEN (clist) && + gtk_clist_row_is_visible (clist, i) != GTK_VISIBILITY_NONE) + GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, i, + GTK_CLIST_ROW (work)); + } +} - case GTK_SELECTION_EXTENDED: - if (event->type != GDK_BUTTON_PRESS) - { - if (clist->anchor != -1) - { - update_extended_selection (clist, clist->focus_row); - GTK_CLIST_CLASS_FW (clist)->resync_selection - (clist, (GdkEvent *) event); - } - select_row (clist, row, column, (GdkEvent *) event); - break; - } - - if (event->state & GDK_CONTROL_MASK) - { - if (event->state & GDK_SHIFT_MASK) - { - if (clist->anchor < 0) - { - g_list_free (clist->undo_selection); - g_list_free (clist->undo_unselection); - clist->undo_selection = NULL; - clist->undo_unselection = NULL; - clist->anchor = old_row; - clist->drag_pos = old_row; - clist->undo_anchor = old_row; - } - update_extended_selection (clist, clist->focus_row); - } - else - { - if (clist->anchor == -1) - set_anchor (clist, TRUE, row, old_row); - else - update_extended_selection (clist, clist->focus_row); - } - break; - } +static void +real_undo_selection (GtkCList *clist) +{ + GList *work; - if (event->state & GDK_SHIFT_MASK) - { - set_anchor (clist, FALSE, old_row, old_row); - update_extended_selection (clist, clist->focus_row); - break; - } + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); - if (clist->anchor == -1) - set_anchor (clist, FALSE, row, old_row); - else - update_extended_selection (clist, clist->focus_row); - break; + if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) || + clist->selection_mode != GTK_SELECTION_EXTENDED) + return; - default: - break; - } - } + if (clist->anchor >= 0) + GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL); - return FALSE; + if (!(clist->undo_selection || clist->undo_unselection)) + { + gtk_clist_unselect_all (clist); + return; } - /* press on resize windows */ - for (i = 0; i < clist->columns; i++) - if (clist->column[i].resizeable && clist->column[i].window && - event->window == clist->column[i].window) - { - gdk_pointer_grab (clist->column[i].window, FALSE, - GDK_POINTER_MOTION_HINT_MASK | - GDK_BUTTON1_MOTION_MASK | - GDK_BUTTON_RELEASE_MASK, - NULL, NULL, event->time); - gtk_grab_add (widget); - GTK_CLIST_SET_FLAG (clist, CLIST_IN_DRAG); - - if (!GTK_WIDGET_HAS_FOCUS (widget)) - gtk_widget_grab_focus (widget); + for (work = clist->undo_selection; work; work = work->next) + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], + GPOINTER_TO_INT (work->data), -1, NULL); - clist->drag_pos = i; - clist->x_drag = (COLUMN_LEFT_XPIXEL(clist, i) + COLUMN_INSET + - clist->column[i].area.width + CELL_SPACING); + for (work = clist->undo_unselection; work; work = work->next) + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], + GPOINTER_TO_INT (work->data), -1, NULL); - if (GTK_CLIST_ADD_MODE (clist)) - gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_SOLID, 0, 0); - draw_xor_line (clist); + if (GTK_WIDGET_HAS_FOCUS (clist) && clist->focus_row != clist->undo_anchor) + { + gtk_clist_draw_focus (GTK_WIDGET (clist)); + clist->focus_row = clist->undo_anchor; + gtk_clist_draw_focus (GTK_WIDGET (clist)); + } + else + clist->focus_row = clist->undo_anchor; + + clist->undo_anchor = -1; + + g_list_free (clist->undo_selection); + g_list_free (clist->undo_unselection); + clist->undo_selection = NULL; + clist->undo_unselection = NULL; - return FALSE; - } - return FALSE; + if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height > + clist->clist_window_height) + gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0); + else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0) + gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0); } -static gint -gtk_clist_button_release (GtkWidget * widget, - GdkEventButton * event) +static void +set_anchor (GtkCList *clist, + gboolean add_mode, + gint anchor, + gint undo_anchor) { - GtkCList *clist; - - g_return_val_if_fail (widget != NULL, FALSE); - g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - - clist = GTK_CLIST (widget); + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); + + if (clist->selection_mode != GTK_SELECTION_EXTENDED || clist->anchor >= 0) + return; - /* we don't handle button 2 and 3 */ - if (event->button != 1) - return FALSE; + g_list_free (clist->undo_selection); + g_list_free (clist->undo_unselection); + clist->undo_selection = NULL; + clist->undo_unselection = NULL; - /* release on resize windows */ - if (GTK_CLIST_IN_DRAG (clist)) + if (add_mode) + fake_toggle_row (clist, anchor); + else { - gint width; - gint x; - gint i; - - i = clist->drag_pos; - clist->drag_pos = -1; + GTK_CLIST_CLASS_FW (clist)->fake_unselect_all (clist, anchor); + clist->anchor_state = GTK_STATE_SELECTED; + } - GTK_CLIST_UNSET_FLAG (clist, CLIST_IN_DRAG); - gtk_widget_get_pointer (widget, &x, NULL); - gtk_grab_remove (widget); - gdk_pointer_ungrab (event->time); + clist->anchor = anchor; + clist->drag_pos = anchor; + clist->undo_anchor = undo_anchor; +} - if (clist->x_drag >= 0) - draw_xor_line (clist); +static void +resync_selection (GtkCList *clist, + GdkEvent *event) +{ + gint i; + gint e; + gint row; + gboolean thaw = FALSE; + GList *list; + GtkCListRow *clist_row; - if (GTK_CLIST_ADD_MODE (clist)) - { - gdk_gc_set_line_attributes (clist->xor_gc, 1, - GDK_LINE_ON_OFF_DASH, 0, 0); - gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2); - } + if (clist->anchor < 0) + return; - width = new_column_width (clist, i, &x); - resize_column (clist, i, width); - return FALSE; + if (!GTK_CLIST_FROZEN (clist)) + { + GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN); + thaw = TRUE; } - if (GTK_CLIST_DRAG_SELECTION (clist)) - { - gint row; - gint column; + i = MIN (clist->anchor, clist->drag_pos); + e = MAX (clist->anchor, clist->drag_pos); - GTK_CLIST_UNSET_FLAG (clist, CLIST_DRAG_SELECTION); - gtk_grab_remove (widget); - gdk_pointer_ungrab (event->time); - if (clist->htimer) - { - gtk_timeout_remove (clist->htimer); - clist->htimer = 0; - } - if (clist->vtimer) - { - gtk_timeout_remove (clist->vtimer); - clist->vtimer = 0; - } - switch (clist->selection_mode) + if (clist->undo_selection) + { + list = clist->selection; + clist->selection = clist->undo_selection; + clist->selection_end = g_list_last (clist->selection); + clist->undo_selection = list; + list = clist->selection; + while (list) { - case GTK_SELECTION_EXTENDED: - if (!(event->state & GDK_SHIFT_MASK) || - event->x < 0 || event->x >= clist->clist_window_width || - event->y < 0 || event->y >= clist->clist_window_height) - GTK_CLIST_CLASS_FW (clist)->resync_selection - (clist, (GdkEvent *) event); - break; - - case GTK_SELECTION_SINGLE: - case GTK_SELECTION_MULTIPLE: - if (get_selection_info (clist, event->x, event->y, &row, &column)) + row = GPOINTER_TO_INT (list->data); + list = list->next; + if (row < i || row > e) { - if (clist->anchor == clist->focus_row) - toggle_row (clist, row, column, (GdkEvent *) event); + clist_row = g_list_nth (clist->row_list, row)->data; + if (clist_row->selectable) + { + clist_row->state = GTK_STATE_SELECTED; + gtk_signal_emit (GTK_OBJECT (clist), + clist_signals[UNSELECT_ROW], + row, -1, event); + clist->undo_selection = g_list_prepend + (clist->undo_selection, GINT_TO_POINTER (row)); + } } - clist->anchor = -1; - break; - - default: - break; } - } - - return FALSE; -} - -static gint -horizontal_timeout (GtkCList *clist) -{ - gint x, y; - GdkEventMotion event; - GdkModifierType mask; - - g_return_val_if_fail (GTK_IS_CLIST (clist), FALSE); + } - clist->htimer = 0; - gdk_window_get_pointer (clist->clist_window, &x, &y, &mask); + for (list = g_list_nth (clist->row_list, i); i <= e; i++, list = list->next) + if (GTK_CLIST_ROW (list)->selectable) + { + if (g_list_find (clist->selection, GINT_TO_POINTER(i))) + { + if (GTK_CLIST_ROW (list)->state == GTK_STATE_NORMAL) + { + GTK_CLIST_ROW (list)->state = GTK_STATE_SELECTED; + gtk_signal_emit (GTK_OBJECT (clist), + clist_signals[UNSELECT_ROW], i, -1, event); + clist->undo_selection = g_list_prepend (clist->undo_selection, + GINT_TO_POINTER (i)); + } + } + else if (GTK_CLIST_ROW (list)->state == GTK_STATE_SELECTED) + { + GTK_CLIST_ROW (list)->state = GTK_STATE_NORMAL; + clist->undo_unselection = g_list_prepend (clist->undo_unselection, + GINT_TO_POINTER (i)); + } + } - event.is_hint = 0; - event.x = x; - event.y = y; - event.state = mask; + for (list = clist->undo_unselection; list; list = list->next) + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], + GPOINTER_TO_INT (list->data), -1, event); - gtk_clist_motion (GTK_WIDGET (clist), &event); + clist->anchor = -1; + clist->drag_pos = -1; - return FALSE; + if (thaw) + GTK_CLIST_UNSET_FLAG (clist, CLIST_FROZEN); } -static gint -vertical_timeout (GtkCList *clist) +static void +update_extended_selection (GtkCList *clist, + gint row) { - gint x, y; - GdkEventMotion event; - GdkModifierType mask; + gint i; + GList *list; + GdkRectangle area; + gint s1 = -1; + gint s2 = -1; + gint e1 = -1; + gint e2 = -1; + gint y1 = clist->clist_window_height; + gint y2 = clist->clist_window_height; + gint h1 = 0; + gint h2 = 0; + gint top; - g_return_val_if_fail (GTK_IS_CLIST (clist), FALSE); + if (clist->selection_mode != GTK_SELECTION_EXTENDED || clist->anchor == -1) + return; - clist->vtimer = 0; - gdk_window_get_pointer (clist->clist_window, &x, &y, &mask); + if (row < 0) + row = 0; + if (row >= clist->rows) + row = clist->rows - 1; - event.is_hint = 0; - event.x = x; - event.y = y; - event.state = mask; + /* extending downwards */ + if (row > clist->drag_pos && clist->anchor <= clist->drag_pos) + { + s2 = clist->drag_pos + 1; + e2 = row; + } + /* extending upwards */ + else if (row < clist->drag_pos && clist->anchor >= clist->drag_pos) + { + s2 = row; + e2 = clist->drag_pos - 1; + } + else if (row < clist->drag_pos && clist->anchor < clist->drag_pos) + { + e1 = clist->drag_pos; + /* row and drag_pos on different sides of anchor : + take back the selection between anchor and drag_pos, + select between anchor and row */ + if (row < clist->anchor) + { + s1 = clist->anchor + 1; + s2 = row; + e2 = clist->anchor - 1; + } + /* take back the selection between anchor and drag_pos */ + else + s1 = row + 1; + } + else if (row > clist->drag_pos && clist->anchor > clist->drag_pos) + { + s1 = clist->drag_pos; + /* row and drag_pos on different sides of anchor : + take back the selection between anchor and drag_pos, + select between anchor and row */ + if (row > clist->anchor) + { + e1 = clist->anchor - 1; + s2 = clist->anchor + 1; + e2 = row; + } + /* take back the selection between anchor and drag_pos */ + else + e1 = row - 1; + } - gtk_clist_motion (GTK_WIDGET (clist), &event); + clist->drag_pos = row; - return FALSE; + area.x = 0; + area.width = clist->clist_window_width; + + /* restore the elements between s1 and e1 */ + if (s1 >= 0) + { + for (i = s1, list = g_list_nth (clist->row_list, i); i <= e1; + i++, list = list->next) + if (GTK_CLIST_ROW (list)->selectable) + { + if (GTK_CLIST_CLASS_FW (clist)->selection_find (clist, i, list)) + GTK_CLIST_ROW (list)->state = GTK_STATE_SELECTED; + else + GTK_CLIST_ROW (list)->state = GTK_STATE_NORMAL; + } + + top = ROW_TOP_YPIXEL (clist, clist->focus_row); + + if (top + clist->row_height <= 0) + { + area.y = 0; + area.height = ROW_TOP_YPIXEL (clist, e1) + clist->row_height; + draw_rows (clist, &area); + gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0); + } + else if (top >= clist->clist_window_height) + { + area.y = ROW_TOP_YPIXEL (clist, s1) - 1; + area.height = clist->clist_window_height - area.y; + draw_rows (clist, &area); + gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0); + } + else if (top < 0) + gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0); + else if (top + clist->row_height > clist->clist_window_height) + gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0); + + y1 = ROW_TOP_YPIXEL (clist, s1) - 1; + h1 = (e1 - s1 + 1) * (clist->row_height + CELL_SPACING); + } + + /* extend the selection between s2 and e2 */ + if (s2 >= 0) + { + for (i = s2, list = g_list_nth (clist->row_list, i); i <= e2; + i++, list = list->next) + if (GTK_CLIST_ROW (list)->selectable && + GTK_CLIST_ROW (list)->state != clist->anchor_state) + GTK_CLIST_ROW (list)->state = clist->anchor_state; + + top = ROW_TOP_YPIXEL (clist, clist->focus_row); + + if (top + clist->row_height <= 0) + { + area.y = 0; + area.height = ROW_TOP_YPIXEL (clist, e2) + clist->row_height; + draw_rows (clist, &area); + gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0); + } + else if (top >= clist->clist_window_height) + { + area.y = ROW_TOP_YPIXEL (clist, s2) - 1; + area.height = clist->clist_window_height - area.y; + draw_rows (clist, &area); + gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0); + } + else if (top < 0) + gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0); + else if (top + clist->row_height > clist->clist_window_height) + gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0); + + y2 = ROW_TOP_YPIXEL (clist, s2) - 1; + h2 = (e2 - s2 + 1) * (clist->row_height + CELL_SPACING); + } + + area.y = MAX (0, MIN (y1, y2)); + if (area.y > clist->clist_window_height) + area.y = 0; + area.height = MIN (clist->clist_window_height, h1 + h2); + if (s1 >= 0 && s2 >= 0) + area.height += (clist->row_height + CELL_SPACING); + draw_rows (clist, &area); } static void -move_vertical (GtkCList *clist, - gint row, - gfloat align) +start_selection (GtkCList *clist) { - gint y; - GtkAdjustment *adj; + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); - adj = GTK_RANGE (clist->vscrollbar)->adjustment; + if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) + return; - y = ROW_TOP_YPIXEL (clist, row) - clist->voffset; - - y = y - align * (clist->clist_window_height - clist->row_height) - + (2 * align - 1) * CELL_SPACING; - - if (y + adj->page_size > adj->upper) - adj->value = adj->upper - adj->page_size; - else - adj->value = y; + set_anchor (clist, GTK_CLIST_ADD_MODE (clist), clist->focus_row, + clist->focus_row); +} - gtk_signal_emit_by_name (GTK_OBJECT (adj), "value_changed"); +static void +end_selection (GtkCList *clist) +{ + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); + + if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_FOCUS (clist)) || + clist->anchor == -1) + return; + + GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL); } static void -move_horizontal (GtkCList *clist, - gint diff) +extend_selection (GtkCList *clist, + GtkScrollType scroll_type, + gfloat position, + gboolean auto_start_selection) { - gfloat upper; - GtkAdjustment *adj; + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); - adj = GTK_RANGE (clist->hscrollbar)->adjustment; + if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) || + clist->selection_mode != GTK_SELECTION_EXTENDED) + return; - adj->value += diff; + if (auto_start_selection) + set_anchor (clist, GTK_CLIST_ADD_MODE (clist), clist->focus_row, + clist->focus_row); + else if (clist->anchor == -1) + return; - upper = adj->upper - adj->page_size; - adj->value = MIN (adj->value, upper); - adj->value = MAX (adj->value, 0.0); + move_focus_row (clist, scroll_type, position); - gtk_signal_emit_by_name (GTK_OBJECT (adj), "value_changed"); + if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height > + clist->clist_window_height) + gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0); + else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0) + gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0); + + update_extended_selection (clist, clist->focus_row); } -static gint -gtk_clist_motion (GtkWidget * widget, - GdkEventMotion * event) +static void +sync_selection (GtkCList *clist, + gint row, + gint mode) { - GtkCList *clist; - gint x; - gint y; - gint row; - gint new_width; - - g_return_val_if_fail (widget != NULL, FALSE); - g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE); - - clist = GTK_CLIST (widget); - if (!(gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))) - return FALSE; + GList *list; + gint d; - if (GTK_CLIST_IN_DRAG (clist)) - { - if (event->is_hint || event->window != widget->window) - gtk_widget_get_pointer (widget, &x, NULL); - else - x = event->x; + if (mode == SYNC_INSERT) + d = 1; + else + d = -1; - new_width = new_column_width (clist, clist->drag_pos, &x); - if (x != clist->x_drag) - { - /* x_drag < 0 indicates that the xor line is already invisible */ - if (clist->x_drag >= 0) - draw_xor_line (clist); + if (clist->focus_row >= row) + { + clist->focus_row += d; + if (clist->focus_row == -1 && clist->rows >= 1) + clist->focus_row = 0; + } - clist->x_drag = x; + if (clist->selection_mode == GTK_SELECTION_BROWSE && clist->anchor != -1) + GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL); - if (clist->x_drag >= 0) - draw_xor_line (clist); - } + g_list_free (clist->undo_selection); + g_list_free (clist->undo_unselection); + clist->undo_selection = NULL; + clist->undo_unselection = NULL; - if (new_width <= MAX (COLUMN_MIN_WIDTH + 1, - clist->column[clist->drag_pos].min_width + 1)) - { - if (COLUMN_LEFT_XPIXEL (clist, clist->drag_pos) < 0 && x < 0) - gtk_clist_moveto (clist, -1, clist->drag_pos, 0, 0); - return FALSE; - } - if (clist->column[clist->drag_pos].max_width >= COLUMN_MIN_WIDTH && - new_width >= clist->column[clist->drag_pos].max_width) - { - if (COLUMN_LEFT_XPIXEL (clist, clist->drag_pos) + new_width > - clist->clist_window_width && x < 0) - move_horizontal (clist, - COLUMN_LEFT_XPIXEL (clist, clist->drag_pos) + - new_width - clist->clist_window_width + - COLUMN_INSET + CELL_SPACING); - return FALSE; - } - } - - if (event->is_hint || event->window != clist->clist_window) - gdk_window_get_pointer (clist->clist_window, &x, &y, NULL); + clist->anchor = -1; + clist->drag_pos = -1; + clist->undo_anchor = clist->focus_row; - /* horizontal autoscrolling */ - if (LIST_WIDTH (clist) > clist->clist_window_width && - (x < 0 || x >= clist->clist_window_width)) + list = clist->selection; + while (list) { - if (clist->htimer) - return FALSE; - - clist->htimer = gtk_timeout_add - (SCROLL_TIME, (GtkFunction) horizontal_timeout, clist); - - if (!((x < 0 && GTK_RANGE (clist->hscrollbar)->adjustment->value == 0) || - (x >= clist->clist_window_width && - GTK_RANGE (clist->hscrollbar)->adjustment->value == - LIST_WIDTH (clist) - clist->clist_window_width))) - { - if (x < 0) - move_horizontal (clist, -1 + (x/2)); - else - move_horizontal (clist, 1 + (x - clist->clist_window_width) / 2); - } + if (GPOINTER_TO_INT (list->data) >= row) + list->data = ((gchar*) list->data) + d; + list = list->next; } +} - if (GTK_CLIST_IN_DRAG (clist)) - return FALSE; - - /* vertical autoscrolling */ - row = ROW_FROM_YPIXEL (clist, y); +/* GTKOBJECT + * gtk_clist_destroy + * gtk_clist_finalize + */ +static void +gtk_clist_destroy (GtkObject *object) +{ + gint i; + GtkCList *clist; - /* don't scroll on last pixel row if it's a cell spacing */ - if (y == clist->clist_window_height-1 && - y == ROW_TOP_YPIXEL (clist, row-1) + clist->row_height) - return FALSE; + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_CLIST (object)); - if (LIST_HEIGHT (clist) > clist->clist_window_height && - (y < 0 || y >= clist->clist_window_height)) - { - if (clist->vtimer) - return FALSE; + clist = GTK_CLIST (object); - clist->vtimer = gtk_timeout_add (SCROLL_TIME, - (GtkFunction) vertical_timeout, clist); + /* freeze the list */ + GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN); - if (GTK_CLIST_DRAG_SELECTION (clist)) - { - if ((y < 0 && clist->focus_row == 0) || - (y >= clist->clist_window_height && - clist->focus_row == clist->rows-1)) - return FALSE; - } - } + /* get rid of all the rows */ + gtk_clist_clear (clist); - row = CLAMP (row, 0, clist->rows - 1); + /* Since we don't have a _remove method, unparent the children + * instead of destroying them so the focus will be unset properly. + * (For other containers, the _remove method takes care of the + * unparent) The destroy will happen when the refcount drops + * to zero. + */ - if (GTK_CLIST_DRAG_SELECTION (clist)) + /* destroy the scrollbars */ + if (clist->vscrollbar) { - if (row == clist->focus_row) - return FALSE; - - gtk_clist_draw_focus (widget); - clist->focus_row = row; - gtk_clist_draw_focus (widget); + gtk_widget_unparent (clist->vscrollbar); + clist->vscrollbar = NULL; + } + if (clist->hscrollbar) + { + gtk_widget_unparent (clist->hscrollbar); + clist->hscrollbar = NULL; + } - switch (clist->selection_mode) - { - case GTK_SELECTION_BROWSE: - select_row (clist, clist->focus_row, - 1, (GdkEvent *) event); - break; - - case GTK_SELECTION_EXTENDED: - update_extended_selection (clist, clist->focus_row); - break; - - default: - break; - } + if (clist->htimer) + { + gtk_timeout_remove (clist->htimer); + clist->htimer = 0; + } + if (clist->vtimer) + { + gtk_timeout_remove (clist->vtimer); + clist->vtimer = 0; } - - if (ROW_TOP_YPIXEL(clist, row) < 0) - move_vertical (clist, row, 0); - else if (ROW_TOP_YPIXEL(clist, row) + clist->row_height > - clist->clist_window_height) - move_vertical (clist, row, 1); - return FALSE; + /* destroy the column buttons */ + for (i = 0; i < clist->columns; i++) + if (clist->column[i].button) + { + gtk_widget_unparent (clist->column[i].button); + clist->column[i].button = NULL; + } + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (*GTK_OBJECT_CLASS (parent_class)->destroy) (object); } static void -gtk_clist_size_request (GtkWidget * widget, - GtkRequisition * requisition) +gtk_clist_finalize (GtkObject *object) { - gint i; GtkCList *clist; - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_CLIST (widget)); - g_return_if_fail (requisition != NULL); - - clist = GTK_CLIST (widget); - - add_style_data (clist); - - requisition->width = 0; - requisition->height = 0; - - /* compute the size of the column title (title) area */ - clist->column_title_area.height = 0; - if (GTK_CLIST_SHOW_TITLES (clist)) - for (i = 0; i < clist->columns; i++) - if (clist->column[i].button) - { - gtk_widget_size_request (clist->column[i].button, - &clist->column[i].button->requisition); - clist->column_title_area.height = - MAX (clist->column_title_area.height, - clist->column[i].button->requisition.height); - } - requisition->height += clist->column_title_area.height; - - /* add the vscrollbar space */ - if ((clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC) || - GTK_WIDGET_VISIBLE (clist->vscrollbar)) - { - gtk_widget_size_request (clist->vscrollbar, - &clist->vscrollbar->requisition); - - requisition->width += (clist->vscrollbar->requisition.width + - SCROLLBAR_SPACING (clist)); - requisition->height = MAX (requisition->height, - clist->vscrollbar->requisition.height); - } + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_CLIST (object)); - /* add the hscrollbar space */ - if ((clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC) || - GTK_WIDGET_VISIBLE (clist->hscrollbar)) - { - gtk_widget_size_request (clist->hscrollbar, - &clist->hscrollbar->requisition); + clist = GTK_CLIST (object); - requisition->height += (clist->hscrollbar->requisition.height + - SCROLLBAR_SPACING (clist)); - requisition->width = MAX (clist->hscrollbar->requisition.width, - requisition->width - - clist->vscrollbar->requisition.width); + columns_delete (clist); - } + g_mem_chunk_destroy (clist->cell_mem_chunk); + g_mem_chunk_destroy (clist->row_mem_chunk); - requisition->width += (widget->style->klass->xthickness * 2 + - GTK_CONTAINER (widget)->border_width * 2); - requisition->height += (widget->style->klass->ythickness * 2 + - GTK_CONTAINER (widget)->border_width * 2); + if (GTK_OBJECT_CLASS (parent_class)->finalize) + (*GTK_OBJECT_CLASS (parent_class)->finalize) (object); } +/* GTKWIDGET + * gtk_clist_realize + * gtk_clist_unrealize + * gtk_clist_map + * gtk_clist_unmap + * gtk_clist_draw + * gtk_clist_expose + * gtk_clist_style_set + * gtk_clist_key_press + * gtk_clist_button_press + * gtk_clist_button_release + * gtk_clist_motion + * gtk_clist_size_request + * gtk_clist_size_allocate + */ static void -gtk_clist_size_allocate (GtkWidget * widget, - GtkAllocation * allocation) +gtk_clist_realize (GtkWidget *widget) { GtkCList *clist; - GtkAllocation clist_allocation; - GtkAllocation child_allocation; - gint i, vscrollbar_vis, hscrollbar_vis; + GdkWindowAttr attributes; + GdkGCValues values; + GtkCListRow *clist_row; + GList *list; + gint attributes_mask; gint border_width; + gint i; + gint j; g_return_if_fail (widget != NULL); g_return_if_fail (GTK_IS_CLIST (widget)); - g_return_if_fail (allocation != NULL); clist = GTK_CLIST (widget); - widget->allocation = *allocation; - border_width = GTK_CONTAINER (widget)->border_width; - if (GTK_WIDGET_REALIZED (widget)) - { - gdk_window_move_resize (widget->window, - allocation->x + border_width, - allocation->y + border_width, - allocation->width - border_width * 2, - allocation->height - border_width * 2); - } + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); - /* use internal allocation structure for all the math - * because it's easier than always subtracting the container - * border width */ - clist->internal_allocation.x = 0; - clist->internal_allocation.y = 0; - clist->internal_allocation.width = MAX (1, allocation->width - - border_width * 2); - clist->internal_allocation.height = MAX (1, allocation->height - - border_width * 2); - - /* allocate clist window assuming no scrollbars */ - clist_allocation.x = (clist->internal_allocation.x + - widget->style->klass->xthickness); - clist_allocation.y = (clist->internal_allocation.y + - widget->style->klass->ythickness + - clist->column_title_area.height); - clist_allocation.width = MAX (1, clist->internal_allocation.width - - (2 * widget->style->klass->xthickness)); - clist_allocation.height = MAX (1, clist->internal_allocation.height - - (2 * widget->style->klass->ythickness) - - clist->column_title_area.height); + border_width = GTK_CONTAINER (widget)->border_width; - /* - * here's where we decide to show/not show the scrollbars - */ - vscrollbar_vis = 0; - hscrollbar_vis = 0; - - for (i = 0; i <= 1; i++) - { - if (LIST_HEIGHT (clist) <= clist_allocation.height && - clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC) - { - vscrollbar_vis = 0; - } - else if (!vscrollbar_vis) - { - vscrollbar_vis = 1; - clist_allocation.width = MAX (1, clist_allocation.width - - (clist->vscrollbar->requisition.width + - SCROLLBAR_SPACING (clist))); - } - - if (LIST_WIDTH (clist) <= clist_allocation.width && - clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC) - { - hscrollbar_vis = 0; - } - else if (!hscrollbar_vis) - { - hscrollbar_vis = 1; - clist_allocation.height = MAX (1, clist_allocation.height - - (clist->hscrollbar->requisition.height - + SCROLLBAR_SPACING (clist))); - } - } - - clist->clist_window_width = clist_allocation.width; - clist->clist_window_height = clist_allocation.height; - - if (GTK_WIDGET_REALIZED (widget)) - { - gdk_window_move_resize (clist->clist_window, - clist_allocation.x, - clist_allocation.y, - clist_allocation.width, - clist_allocation.height); - } + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = widget->allocation.x + border_width; + attributes.y = widget->allocation.y + border_width; + attributes.width = widget->allocation.width - border_width * 2; + attributes.height = widget->allocation.height - border_width * 2; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget); + attributes.event_mask |= (GDK_EXPOSURE_MASK | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_KEY_PRESS_MASK | + GDK_KEY_RELEASE_MASK); + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + + /* main window */ + widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), + &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, clist); + + widget->style = gtk_style_attach (widget->style, widget->window); + + gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); + + /* column-title window */ + + attributes.x = clist->column_title_area.x; + attributes.y = clist->column_title_area.y; + attributes.width = clist->column_title_area.width; + attributes.height = clist->column_title_area.height; - /* position the window which holds the column title buttons */ - clist->column_title_area.x = widget->style->klass->xthickness; - clist->column_title_area.y = widget->style->klass->ythickness; - clist->column_title_area.width = clist_allocation.width; + clist->title_window = gdk_window_new (widget->window, &attributes, + attributes_mask); + gdk_window_set_user_data (clist->title_window, clist); + + gtk_style_set_background (widget->style, clist->title_window, + GTK_STATE_SELECTED); + gdk_window_show (clist->title_window); + + /* set things up so column buttons are drawn in title window */ + for (i = 0; i < clist->columns; i++) + if (clist->column[i].button) + gtk_widget_set_parent_window (clist->column[i].button, + clist->title_window); + + /* clist-window */ + attributes.x = (clist->internal_allocation.x + + widget->style->klass->xthickness); + attributes.y = (clist->internal_allocation.y + + widget->style->klass->ythickness + + clist->column_title_area.height); + attributes.width = clist->clist_window_width; + attributes.height = clist->clist_window_height; - if (GTK_WIDGET_REALIZED (widget)) + clist->clist_window = gdk_window_new (widget->window, &attributes, + attributes_mask); + gdk_window_set_user_data (clist->clist_window, clist); + + gdk_window_set_background (clist->clist_window, + &widget->style->bg[GTK_STATE_PRELIGHT]); + gdk_window_show (clist->clist_window); + gdk_window_get_size (clist->clist_window, &clist->clist_window_width, + &clist->clist_window_height); + + /* create resize windows */ + attributes.wclass = GDK_INPUT_ONLY; + attributes.event_mask = (GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_POINTER_MOTION_MASK | + GDK_POINTER_MOTION_HINT_MASK | + GDK_KEY_PRESS_MASK); + attributes_mask = GDK_WA_CURSOR; + attributes.cursor = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW); + clist->cursor_drag = attributes.cursor; + + attributes.x = LIST_WIDTH (clist) + 1; + attributes.y = 0; + attributes.width = 0; + attributes.height = 0; + + for (i = 0; i < clist->columns; i++) { - gdk_window_move_resize (clist->title_window, - clist->column_title_area.x, - clist->column_title_area.y, - clist->column_title_area.width, - clist->column_title_area.height); + clist->column[i].window = gdk_window_new (clist->title_window, + &attributes, attributes_mask); + gdk_window_set_user_data (clist->column[i].window, clist); } - - /* column button allocation */ - size_allocate_columns (clist); + + /* This is slightly less efficient than creating them with the + * right size to begin with, but easier + */ size_allocate_title_buttons (clist); - adjust_scrollbars (clist); - - /* allocate the vscrollbar */ - if (vscrollbar_vis) - { - if (!GTK_WIDGET_VISIBLE (clist->vscrollbar)) - gtk_widget_show (clist->vscrollbar); - - child_allocation.x = (clist->internal_allocation.x + - clist->internal_allocation.width - - clist->vscrollbar->requisition.width); - child_allocation.y = clist->internal_allocation.y; - child_allocation.width = clist->vscrollbar->requisition.width; - child_allocation.height = MAX (1, clist->internal_allocation.height - - (hscrollbar_vis ? - (clist->hscrollbar->requisition.height + - SCROLLBAR_SPACING (clist)) : 0)); - gtk_widget_size_allocate (clist->vscrollbar, &child_allocation); - } - else - { - if (GTK_WIDGET_VISIBLE (clist->vscrollbar)) - gtk_widget_hide (clist->vscrollbar); - } + /* GCs */ + clist->fg_gc = gdk_gc_new (widget->window); + clist->bg_gc = gdk_gc_new (widget->window); - if (hscrollbar_vis) + /* We'll use this gc to do scrolling as well */ + gdk_gc_set_exposures (clist->fg_gc, TRUE); + + values.foreground = widget->style->white; + values.function = GDK_XOR; + values.subwindow_mode = GDK_INCLUDE_INFERIORS; + clist->xor_gc = gdk_gc_new_with_values (widget->window, + &values, + GDK_GC_FOREGROUND | + GDK_GC_FUNCTION | + GDK_GC_SUBWINDOW); + + /* attach optional row/cell styles, allocate foreground/background colors */ + list = clist->row_list; + for (i = 0; i < clist->rows; i++) { - if (!GTK_WIDGET_VISIBLE (clist->hscrollbar)) - gtk_widget_show (clist->hscrollbar); - - child_allocation.x = clist->internal_allocation.x; - child_allocation.y = (clist->internal_allocation.y + - clist->internal_allocation.height - - clist->hscrollbar->requisition.height); - child_allocation.width = MAX (1, clist->internal_allocation.width - - (vscrollbar_vis ? - (clist->vscrollbar->requisition.width + - SCROLLBAR_SPACING (clist)) : 0)); - child_allocation.height = clist->hscrollbar->requisition.height; + clist_row = list->data; + list = list->next; + + if (clist_row->style) + clist_row->style = gtk_style_attach (clist_row->style, + clist->clist_window); + + if (clist_row->fg_set || clist_row->bg_set) + { + GdkColormap *colormap; + + colormap = gtk_widget_get_colormap (widget); + if (clist_row->fg_set) + gdk_color_alloc (colormap, &clist_row->foreground); + if (clist_row->bg_set) + gdk_color_alloc (colormap, &clist_row->background); + } - gtk_widget_size_allocate (clist->hscrollbar, &child_allocation); - } - else - { - if (GTK_WIDGET_VISIBLE (clist->hscrollbar)) - gtk_widget_hide (clist->hscrollbar); + for (j = 0; j < clist->columns; j++) + if (clist_row->cell[j].style) + clist_row->cell[j].style = + gtk_style_attach (clist_row->cell[j].style, clist->clist_window); } - - /* set the vscrollbar adjustments */ - adjust_scrollbars (clist); } -/* - * GTKCONTAINER - * gtk_clist_forall - */ static void -gtk_clist_forall (GtkContainer *container, - gboolean include_internals, - GtkCallback callback, - gpointer callback_data) +gtk_clist_unrealize (GtkWidget *widget) { + gint i; GtkCList *clist; - g_return_if_fail (container != NULL); - g_return_if_fail (GTK_IS_CLIST (container)); - g_return_if_fail (callback != NULL); + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CLIST (widget)); - clist = GTK_CLIST (container); - - if (include_internals) + clist = GTK_CLIST (widget); + + GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN); + + /* detach optional row/cell styles */ + + if (GTK_WIDGET_REALIZED (widget)) { - guint i; - - /* callback for the column buttons */ - for (i = 0; i < clist->columns; i++) - if (clist->column[i].button) - (*callback) (clist->column[i].button, callback_data); - - /* callbacks for the scrollbars */ - if (clist->vscrollbar) - (*callback) (clist->vscrollbar, callback_data); - if (clist->hscrollbar) - (*callback) (clist->hscrollbar, callback_data); - } -} - -/* - * DRAWING - * get_cell_style - * draw_cell_pixmap - * draw_row - * draw_rows - */ - -static void -get_cell_style (GtkCList *clist, - GtkCListRow *clist_row, - gint state, - gint column, - GtkStyle **style, - GdkGC **fg_gc, - GdkGC **bg_gc) -{ - if (clist_row->cell[column].style) - { - if (style) - *style = clist_row->cell[column].style; - if (fg_gc) - *fg_gc = clist_row->cell[column].style->fg_gc[state]; - if (bg_gc) - *bg_gc = clist_row->cell[column].style->bg_gc[state]; - } - else if (clist_row->style) - { - if (style) - *style = clist_row->style; - if (fg_gc) - *fg_gc = clist_row->style->fg_gc[state]; - if (bg_gc) - *bg_gc = clist_row->style->bg_gc[state]; - } - else - { - if (style) - *style = GTK_WIDGET (clist)->style; - if (fg_gc) - *fg_gc = GTK_WIDGET (clist)->style->fg_gc[state]; - if (bg_gc) - *bg_gc = GTK_WIDGET (clist)->style->bg_gc[state]; + GtkCListRow *clist_row; + GList *list; + gint j; - if (state != GTK_STATE_SELECTED) + list = clist->row_list; + for (i = 0; i < clist->rows; i++) { - if (fg_gc && clist_row->fg_set) - *fg_gc = clist->fg_gc; - if (bg_gc && clist_row->bg_set) - *bg_gc = clist->bg_gc; + clist_row = list->data; + list = list->next; + + if (clist_row->style) + gtk_style_detach (clist_row->style); + for (j = 0; j < clist->columns; j++) + if (clist_row->cell[j].style) + gtk_style_detach (clist_row->cell[j].style); } } -} -static gint -draw_cell_pixmap (GdkWindow *window, - GdkRectangle *clip_rectangle, - GdkGC *fg_gc, - GdkPixmap *pixmap, - GdkBitmap *mask, - gint x, - gint y, - gint width, - gint height) -{ - gint xsrc = 0; - gint ysrc = 0; + gdk_cursor_destroy (clist->cursor_drag); + gdk_gc_destroy (clist->xor_gc); + gdk_gc_destroy (clist->fg_gc); + gdk_gc_destroy (clist->bg_gc); - if (mask) - { - gdk_gc_set_clip_mask (fg_gc, mask); - gdk_gc_set_clip_origin (fg_gc, x, y); - } + for (i = 0; i < clist->columns; i++) + if (clist->column[i].window) + { + gdk_window_set_user_data (clist->column[i].window, NULL); + gdk_window_destroy (clist->column[i].window); + clist->column[i].window = NULL; + } - if (x < clip_rectangle->x) - { - xsrc = clip_rectangle->x - x; - width -= xsrc; - x = clip_rectangle->x; - } - if (x + width > clip_rectangle->x + clip_rectangle->width) - width = clip_rectangle->x + clip_rectangle->width - x; + gdk_window_set_user_data (clist->clist_window, NULL); + gdk_window_destroy (clist->clist_window); + clist->clist_window = NULL; - if (y < clip_rectangle->y) - { - ysrc = clip_rectangle->y - y; - height -= ysrc; - y = clip_rectangle->y; - } - if (y + height > clip_rectangle->y + clip_rectangle->height) - height = clip_rectangle->y + clip_rectangle->height - y; + gdk_window_set_user_data (clist->title_window, NULL); + gdk_window_destroy (clist->title_window); + clist->title_window = NULL; - gdk_draw_pixmap (window, fg_gc, pixmap, xsrc, ysrc, x, y, width, height); - gdk_gc_set_clip_origin (fg_gc, 0, 0); + clist->cursor_drag = NULL; + clist->xor_gc = NULL; + clist->fg_gc = NULL; + clist->bg_gc = NULL; - return x + MAX (width, 0); + if (GTK_WIDGET_CLASS (parent_class)->unrealize) + (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget); } static void -draw_row (GtkCList * clist, - GdkRectangle * area, - gint row, - GtkCListRow * clist_row) +gtk_clist_map (GtkWidget *widget) { - GtkWidget *widget; - GdkRectangle *rect; - GdkRectangle row_rectangle; - GdkRectangle cell_rectangle; - GdkRectangle clip_rectangle; - GdkRectangle intersect_rectangle; - gint state; gint i; + GtkCList *clist; - g_return_if_fail (clist != NULL); - - /* bail now if we arn't drawable yet */ - if (!GTK_WIDGET_DRAWABLE (clist) || row < 0 || row >= clist->rows) - return; + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CLIST (widget)); - widget = GTK_WIDGET (clist); + clist = GTK_CLIST (widget); - /* if the function is passed the pointer to the row instead of null, - * it avoids this expensive lookup */ - if (!clist_row) - clist_row = (g_list_nth (clist->row_list, row))->data; + if (!GTK_WIDGET_MAPPED (widget)) + { + GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); - /* rectangle of the entire row */ - row_rectangle.x = 0; - row_rectangle.y = ROW_TOP_YPIXEL (clist, row); - row_rectangle.width = clist->clist_window_width; - row_rectangle.height = clist->row_height; + gdk_window_show (widget->window); + gdk_window_show (clist->title_window); + gdk_window_show (clist->clist_window); - /* rectangle of the cell spacing above the row */ - cell_rectangle.x = 0; - cell_rectangle.y = row_rectangle.y - CELL_SPACING; - cell_rectangle.width = row_rectangle.width; - cell_rectangle.height = CELL_SPACING; + /* map column buttons */ + for (i = 0; i < clist->columns; i++) + if (clist->column[i].button && + GTK_WIDGET_VISIBLE (clist->column[i].button) && + !GTK_WIDGET_MAPPED (clist->column[i].button)) + gtk_widget_map (clist->column[i].button); + + /* map resize windows AFTER column buttons (above) */ + for (i = 0; i < clist->columns; i++) + if (clist->column[i].window && clist->column[i].button) + gdk_window_show (clist->column[i].window); + + /* map vscrollbars */ + if (GTK_WIDGET_VISIBLE (clist->vscrollbar) && + !GTK_WIDGET_MAPPED (clist->vscrollbar)) + gtk_widget_map (clist->vscrollbar); - /* rectangle used to clip drawing operations, it's y and height - * positions only need to be set once, so we set them once here. - * the x and width are set withing the drawing loop below once per - * column */ - clip_rectangle.y = row_rectangle.y; - clip_rectangle.height = row_rectangle.height; + if (GTK_WIDGET_VISIBLE (clist->hscrollbar) && + !GTK_WIDGET_MAPPED (clist->hscrollbar)) + gtk_widget_map (clist->hscrollbar); - if (clist_row->state == GTK_STATE_NORMAL) - { - state = GTK_STATE_PRELIGHT; - if (clist_row->fg_set) - gdk_gc_set_foreground (clist->fg_gc, &clist_row->foreground); - if (clist_row->bg_set) - gdk_gc_set_foreground (clist->bg_gc, &clist_row->background); + /* unfreeze the list */ + GTK_CLIST_UNSET_FLAG (clist, CLIST_FROZEN); } - else - state = clist_row->state; - - /* draw the cell borders and background */ - if (area) - { - rect = &intersect_rectangle; - if (gdk_rectangle_intersect (area, &cell_rectangle, - &intersect_rectangle)) - gdk_draw_rectangle (clist->clist_window, - widget->style->base_gc[GTK_STATE_NORMAL], - TRUE, - intersect_rectangle.x, - intersect_rectangle.y, - intersect_rectangle.width, - intersect_rectangle.height); +} - /* the last row has to clear it's bottom cell spacing too */ - if (clist_row == clist->row_list_end->data) - { - cell_rectangle.y += clist->row_height + CELL_SPACING; +static void +gtk_clist_unmap (GtkWidget *widget) +{ + gint i; + GtkCList *clist; - if (gdk_rectangle_intersect (area, &cell_rectangle, - &intersect_rectangle)) - gdk_draw_rectangle (clist->clist_window, - widget->style->base_gc[GTK_STATE_NORMAL], - TRUE, - intersect_rectangle.x, - intersect_rectangle.y, - intersect_rectangle.width, - intersect_rectangle.height); - } + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CLIST (widget)); - if (!gdk_rectangle_intersect (area, &row_rectangle,&intersect_rectangle)) - return; + clist = GTK_CLIST (widget); - } - else + if (GTK_WIDGET_MAPPED (widget)) { - rect = &clip_rectangle; - gdk_draw_rectangle (clist->clist_window, - widget->style->base_gc[GTK_STATE_NORMAL], - TRUE, - cell_rectangle.x, - cell_rectangle.y, - cell_rectangle.width, - cell_rectangle.height); + GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); - /* the last row has to clear it's bottom cell spacing too */ - if (clist_row == clist->row_list_end->data) - { - cell_rectangle.y += clist->row_height + CELL_SPACING; + for (i = 0; i < clist->columns; i++) + if (clist->column[i].window) + gdk_window_hide (clist->column[i].window); - gdk_draw_rectangle (clist->clist_window, - widget->style->base_gc[GTK_STATE_NORMAL], - TRUE, - cell_rectangle.x, - cell_rectangle.y, - cell_rectangle.width, - cell_rectangle.height); - } - } - - /* iterate and draw all the columns (row cells) and draw their contents */ - for (i = 0; i < clist->columns; i++) - { - GtkStyle *style; - GdkGC *fg_gc; - GdkGC *bg_gc; + gdk_window_hide (clist->clist_window); + gdk_window_hide (clist->title_window); + gdk_window_hide (widget->window); - gint width; - gint height; - gint pixmap_width; - gint offset = 0; - gint row_center_offset; + /* unmap scrollbars */ + if (GTK_WIDGET_MAPPED (clist->vscrollbar)) + gtk_widget_unmap (clist->vscrollbar); - if (!clist->column[i].visible) - continue; + if (GTK_WIDGET_MAPPED (clist->hscrollbar)) + gtk_widget_unmap (clist->hscrollbar); - get_cell_style (clist, clist_row, state, i, &style, &fg_gc, &bg_gc); + /* unmap column buttons */ + for (i = 0; i < clist->columns; i++) + if (clist->column[i].button && + GTK_WIDGET_MAPPED (clist->column[i].button)) + gtk_widget_unmap (clist->column[i].button); - clip_rectangle.x = clist->column[i].area.x + clist->hoffset; - clip_rectangle.width = clist->column[i].area.width; + /* freeze the list */ + GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN); + } +} - /* calculate clipping region clipping region */ - clip_rectangle.x -= COLUMN_INSET + CELL_SPACING; - clip_rectangle.width += (2 * COLUMN_INSET + CELL_SPACING + - (i + 1 == clist->columns) * CELL_SPACING); - - if (area && !gdk_rectangle_intersect (area, &clip_rectangle, - &intersect_rectangle)) - continue; +static void +gtk_clist_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GtkCList *clist; + gint border_width; + GdkRectangle child_area; + int i; - gdk_draw_rectangle (clist->clist_window, bg_gc, TRUE, - rect->x, rect->y, rect->width, rect->height); + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CLIST (widget)); + g_return_if_fail (area != NULL); - clip_rectangle.x += COLUMN_INSET + CELL_SPACING; - clip_rectangle.width -= (2 * COLUMN_INSET + CELL_SPACING + - (i + 1 == clist->columns) * CELL_SPACING); + if (GTK_WIDGET_DRAWABLE (widget)) + { + clist = GTK_CLIST (widget); + border_width = GTK_CONTAINER (widget)->border_width; - /* calculate real width for column justification */ - pixmap_width = 0; - offset = 0; - switch (clist_row->cell[i].type) + gdk_window_clear_area (widget->window, + area->x - border_width, + area->y - border_width, + area->width, area->height); + + /* draw list shadow/border */ + gtk_draw_shadow (widget->style, widget->window, + GTK_STATE_NORMAL, clist->shadow_type, + 0, 0, + clist->clist_window_width + + (2 * widget->style->klass->xthickness), + clist->clist_window_height + + (2 * widget->style->klass->ythickness) + + clist->column_title_area.height); + + gdk_window_clear_area (clist->clist_window, 0, 0, -1, -1); + draw_rows (clist, NULL); + + for (i = 0; i < clist->columns; i++) { - case GTK_CELL_TEXT: - width = gdk_string_width (style->font, - GTK_CELL_TEXT (clist_row->cell[i])->text); - break; - case GTK_CELL_PIXMAP: - gdk_window_get_size (GTK_CELL_PIXMAP (clist_row->cell[i])->pixmap, - &pixmap_width, &height); - width = pixmap_width; - break; - case GTK_CELL_PIXTEXT: - gdk_window_get_size (GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap, - &pixmap_width, &height); - width = (pixmap_width + - GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing + - gdk_string_width (style->font, - GTK_CELL_PIXTEXT - (clist_row->cell[i])->text)); - break; - default: - continue; - break; + if (!clist->column[i].visible) + continue; + if (gtk_widget_intersect(clist->column[i].button, area, &child_area)) + gtk_widget_draw (clist->column[i].button, &child_area); } + } +} - switch (clist->column[i].justification) - { - case GTK_JUSTIFY_LEFT: - offset = clip_rectangle.x + clist_row->cell[i].horizontal; - break; - case GTK_JUSTIFY_RIGHT: - offset = (clip_rectangle.x + clist_row->cell[i].horizontal + - clip_rectangle.width - width); - break; - case GTK_JUSTIFY_CENTER: - case GTK_JUSTIFY_FILL: - offset = (clip_rectangle.x + clist_row->cell[i].horizontal + - (clip_rectangle.width / 2) - (width / 2)); - break; - }; +static gint +gtk_clist_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkCList *clist; - /* Draw Text and/or Pixmap */ - switch (clist_row->cell[i].type) - { - case GTK_CELL_PIXMAP: - draw_cell_pixmap (clist->clist_window, &clip_rectangle, fg_gc, - GTK_CELL_PIXMAP (clist_row->cell[i])->pixmap, - GTK_CELL_PIXMAP (clist_row->cell[i])->mask, - offset, - clip_rectangle.y + clist_row->cell[i].vertical + - (clip_rectangle.height - height) / 2, - pixmap_width, height); - break; - case GTK_CELL_PIXTEXT: - offset = - draw_cell_pixmap (clist->clist_window, &clip_rectangle, fg_gc, - GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap, - GTK_CELL_PIXTEXT (clist_row->cell[i])->mask, - offset, - clip_rectangle.y + clist_row->cell[i].vertical+ - (clip_rectangle.height - height) / 2, - pixmap_width, height); - offset += GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing; - case GTK_CELL_TEXT: - if (style != GTK_WIDGET (clist)->style) - row_center_offset = (((clist->row_height - style->font->ascent - - style->font->descent - 1) / 2) + 1.5 + - style->font->ascent); - else - row_center_offset = clist->row_center_offset; + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); - gdk_gc_set_clip_rectangle (fg_gc, &clip_rectangle); - gdk_draw_string (clist->clist_window, style->font, fg_gc, - offset, - row_rectangle.y + row_center_offset + - clist_row->cell[i].vertical, - (clist_row->cell[i].type == GTK_CELL_PIXTEXT) ? - GTK_CELL_PIXTEXT (clist_row->cell[i])->text : - GTK_CELL_TEXT (clist_row->cell[i])->text); - gdk_gc_set_clip_rectangle (fg_gc, NULL); - break; - default: - break; - } + if (GTK_WIDGET_DRAWABLE (widget)) + { + clist = GTK_CLIST (widget); + + /* draw border */ + if (event->window == widget->window) + gtk_draw_shadow (widget->style, widget->window, + GTK_STATE_NORMAL, clist->shadow_type, + 0, 0, + clist->clist_window_width + + (2 * widget->style->klass->xthickness), + clist->clist_window_height + + (2 * widget->style->klass->ythickness) + + clist->column_title_area.height); + + /* exposure events on the list */ + if (event->window == clist->clist_window) + draw_rows (clist, &event->area); } - /* draw focus rectangle */ - if (clist->focus_row == row && GTK_WIDGET_HAS_FOCUS (widget)) + return FALSE; +} + +static void +gtk_clist_style_set (GtkWidget *widget, + GtkStyle *previous_style) +{ + GtkCList *clist; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CLIST (widget)); + + if (GTK_WIDGET_CLASS (parent_class)->style_set) + (*GTK_WIDGET_CLASS (parent_class)->style_set) (widget, previous_style); + + clist = GTK_CLIST (widget); + + /* Fill in data after widget has correct style */ + + /* text properties */ + if (!GTK_CLIST_ROW_HEIGHT_SET (clist)) { - if (!area) - gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, - row_rectangle.x, row_rectangle.y, - row_rectangle.width - 1, row_rectangle.height - 1); - else if (gdk_rectangle_intersect (area, &row_rectangle, - &intersect_rectangle)) - { - gdk_gc_set_clip_rectangle (clist->xor_gc, &intersect_rectangle); - gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, - row_rectangle.x, row_rectangle.y, - row_rectangle.width - 1, - row_rectangle.height - 1); - gdk_gc_set_clip_rectangle (clist->xor_gc, NULL); - } + clist->row_height = (widget->style->font->ascent + + widget->style->font->descent + 1); + clist->row_center_offset = widget->style->font->ascent + 1.5; + } + else + clist->row_center_offset = 1.5 + (clist->row_height + + widget->style->font->ascent - + widget->style->font->descent - 1) / 2; + + /* Column widths */ + if (!GTK_CLIST_AUTO_RESIZE_BLOCKED (clist)) + { + gint width; + gint i; + + for (i = 0; i < clist->columns; i++) + if (clist->column[i].auto_resize) + { + width = gtk_clist_optimal_column_width (clist, i); + if (width != clist->column[i].width) + gtk_clist_set_column_width (clist, i, width); + } } } -static void -draw_rows (GtkCList * clist, - GdkRectangle * area) -{ - GList *list; - GtkCListRow *clist_row; - int i, first_row, last_row; +static gint +gtk_clist_key_press (GtkWidget *widget, + GdkEventKey *event) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_CLASS (parent_class)->key_press_event && + GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event)) + return TRUE; + + switch (event->keyval) + { + case GDK_Tab: + case GDK_ISO_Left_Tab: + if (event->state & GDK_SHIFT_MASK) + return gtk_container_focus (GTK_CONTAINER (widget), + GTK_DIR_TAB_BACKWARD); + else + return gtk_container_focus (GTK_CONTAINER (widget), + GTK_DIR_TAB_FORWARD); + default: + break; + } + return FALSE; +} + +static gint +gtk_clist_button_press (GtkWidget *widget, + GdkEventButton *event) +{ + gint i; + GtkCList *clist; + gint x; + gint y; + gint row; + gint column; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + clist = GTK_CLIST (widget); + + /* we don't handle button 2 and 3 */ + if (event->button != 1) + return FALSE; + + /* selections on the list */ + if (event->window == clist->clist_window) + { + x = event->x; + y = event->y; + + if (get_selection_info (clist, x, y, &row, &column)) + { + gint old_row = clist->focus_row; + + if (clist->focus_row == -1) + old_row = row; + + if (event->type == GDK_BUTTON_PRESS) + { + GTK_CLIST_SET_FLAG (clist, CLIST_DRAG_SELECTION); + gdk_pointer_grab (clist->clist_window, FALSE, + GDK_POINTER_MOTION_HINT_MASK | + GDK_BUTTON1_MOTION_MASK | + GDK_BUTTON_RELEASE_MASK, + NULL, NULL, event->time); + gtk_grab_add (widget); + } + else if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (widget)) + { + GTK_CLIST_UNSET_FLAG (clist, CLIST_DRAG_SELECTION); + gtk_grab_remove (widget); + gdk_pointer_ungrab (event->time); + } + + if (GTK_CLIST_ADD_MODE (clist)) + { + GTK_CLIST_UNSET_FLAG (clist, CLIST_ADD_MODE); + if (GTK_WIDGET_HAS_FOCUS (widget)) + { + gtk_clist_draw_focus (widget); + gdk_gc_set_line_attributes (clist->xor_gc, 1, + GDK_LINE_SOLID, 0, 0); + clist->focus_row = row; + gtk_clist_draw_focus (widget); + } + else + { + gdk_gc_set_line_attributes (clist->xor_gc, 1, + GDK_LINE_SOLID, 0, 0); + clist->focus_row = row; + } + } + else if (row != clist->focus_row) + { + if (GTK_WIDGET_HAS_FOCUS (widget)) + { + gtk_clist_draw_focus (widget); + clist->focus_row = row; + gtk_clist_draw_focus (widget); + } + else + clist->focus_row = row; + } + + if (!GTK_WIDGET_HAS_FOCUS (widget)) + gtk_widget_grab_focus (widget); - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); + switch (clist->selection_mode) + { + case GTK_SELECTION_SINGLE: + case GTK_SELECTION_MULTIPLE: + if (event->type != GDK_BUTTON_PRESS) + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], + row, column, event); + else + clist->anchor = row; + break; + case GTK_SELECTION_BROWSE: + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], + row, column, event); + break; + case GTK_SELECTION_EXTENDED: + if (event->type != GDK_BUTTON_PRESS) + { + if (clist->anchor != -1) + { + update_extended_selection (clist, clist->focus_row); + GTK_CLIST_CLASS_FW (clist)->resync_selection + (clist, (GdkEvent *) event); + } + gtk_signal_emit (GTK_OBJECT (clist), + clist_signals[SELECT_ROW], + row, column, event); + break; + } + + if (event->state & GDK_CONTROL_MASK) + { + if (event->state & GDK_SHIFT_MASK) + { + if (clist->anchor < 0) + { + g_list_free (clist->undo_selection); + g_list_free (clist->undo_unselection); + clist->undo_selection = NULL; + clist->undo_unselection = NULL; + clist->anchor = old_row; + clist->drag_pos = old_row; + clist->undo_anchor = old_row; + } + update_extended_selection (clist, clist->focus_row); + } + else + { + if (clist->anchor == -1) + set_anchor (clist, TRUE, row, old_row); + else + update_extended_selection (clist, clist->focus_row); + } + break; + } - if (clist->row_height == 0 || - !GTK_WIDGET_DRAWABLE (clist)) - return; + if (event->state & GDK_SHIFT_MASK) + { + set_anchor (clist, FALSE, old_row, old_row); + update_extended_selection (clist, clist->focus_row); + break; + } - if (area) - { - first_row = ROW_FROM_YPIXEL (clist, area->y); - last_row = ROW_FROM_YPIXEL (clist, area->y + area->height); - } - else - { - first_row = ROW_FROM_YPIXEL (clist, 0); - last_row = ROW_FROM_YPIXEL (clist, clist->clist_window_height); + if (clist->anchor == -1) + set_anchor (clist, FALSE, row, old_row); + else + update_extended_selection (clist, clist->focus_row); + break; + default: + break; + } + } + + return FALSE; } - /* this is a small special case which exposes the bottom cell line - * on the last row -- it might go away if I change the wall the cell spacings - * are drawn */ - if (clist->rows == first_row) - first_row--; + /* press on resize windows */ + for (i = 0; i < clist->columns; i++) + if (clist->column[i].resizeable && clist->column[i].window && + event->window == clist->column[i].window) + { + gdk_pointer_grab (clist->column[i].window, FALSE, + GDK_POINTER_MOTION_HINT_MASK | + GDK_BUTTON1_MOTION_MASK | + GDK_BUTTON_RELEASE_MASK, + NULL, NULL, event->time); + gtk_grab_add (widget); + GTK_CLIST_SET_FLAG (clist, CLIST_IN_DRAG); - list = g_list_nth (clist->row_list, first_row); - i = first_row; - while (list) - { - clist_row = list->data; - list = list->next; + if (!GTK_WIDGET_HAS_FOCUS (widget)) + gtk_widget_grab_focus (widget); - if (i > last_row) - return; + clist->drag_pos = i; + clist->x_drag = (COLUMN_LEFT_XPIXEL(clist, i) + COLUMN_INSET + + clist->column[i].area.width + CELL_SPACING); - GTK_CLIST_CLASS_FW (clist)->draw_row (clist, area, i, clist_row); - i++; - } + if (GTK_CLIST_ADD_MODE (clist)) + gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_SOLID, 0, 0); + draw_xor_line (clist); - if (!area) - gdk_window_clear_area (clist->clist_window, 0, ROW_TOP_YPIXEL (clist, i), -1, -1); + return FALSE; + } + return FALSE; } -/* - * SIZE ALLOCATION - * size_allocate_title_buttons - * size_allocate_columns - */ -static void -size_allocate_title_buttons (GtkCList * clist) +static gint +gtk_clist_button_release (GtkWidget *widget, + GdkEventButton *event) { - GtkAllocation button_allocation; - gint last_column; - gint last_button = 0; - gint i; + GtkCList *clist; - if (!GTK_WIDGET_REALIZED (clist)) - return; + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); - button_allocation.x = clist->hoffset; - button_allocation.y = 0; - button_allocation.width = 0; - button_allocation.height = clist->column_title_area.height; + clist = GTK_CLIST (widget); - /* find last visible column */ - for (last_column = clist->columns - 1; last_column >= 0; last_column--) - if (clist->column[last_column].visible) - break; + /* we don't handle button 2 and 3 */ + if (event->button != 1) + return FALSE; - for (i = 0; i < last_column; i++) + /* release on resize windows */ + if (GTK_CLIST_IN_DRAG (clist)) { - if (!clist->column[i].visible) - { - last_button = i + 1; - gdk_window_hide (clist->column[i].window); - continue; - } + gint width; + gint x; + gint i; - button_allocation.width += (clist->column[i].area.width + - CELL_SPACING + 2 * COLUMN_INSET); + i = clist->drag_pos; + clist->drag_pos = -1; - if (!clist->column[i + 1].button) + GTK_CLIST_UNSET_FLAG (clist, CLIST_IN_DRAG); + gtk_widget_get_pointer (widget, &x, NULL); + gtk_grab_remove (widget); + gdk_pointer_ungrab (event->time); + + if (clist->x_drag >= 0) + draw_xor_line (clist); + + if (GTK_CLIST_ADD_MODE (clist)) { - gdk_window_hide (clist->column[i].window); - continue; + gdk_gc_set_line_attributes (clist->xor_gc, 1, + GDK_LINE_ON_OFF_DASH, 0, 0); + gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2); } - gtk_widget_size_allocate (clist->column[last_button].button, - &button_allocation); - button_allocation.x += button_allocation.width; - button_allocation.width = 0; + width = new_column_width (clist, i, &x); + gtk_clist_set_column_width (clist, i, width); + return FALSE; + } - if (clist->column[last_button].resizeable) + if (GTK_CLIST_DRAG_SELECTION (clist)) + { + gint row; + gint column; + + GTK_CLIST_UNSET_FLAG (clist, CLIST_DRAG_SELECTION); + gtk_grab_remove (widget); + gdk_pointer_ungrab (event->time); + if (clist->htimer) { - gdk_window_show (clist->column[last_button].window); - gdk_window_move_resize (clist->column[last_button].window, - button_allocation.x - (DRAG_WIDTH / 2), - 0, DRAG_WIDTH, - clist->column_title_area.height); + gtk_timeout_remove (clist->htimer); + clist->htimer = 0; } - else - gdk_window_hide (clist->column[last_button].window); + if (clist->vtimer) + { + gtk_timeout_remove (clist->vtimer); + clist->vtimer = 0; + } + switch (clist->selection_mode) + { + case GTK_SELECTION_EXTENDED: + if (!(event->state & GDK_SHIFT_MASK) || + event->x < 0 || event->x >= clist->clist_window_width || + event->y < 0 || event->y >= clist->clist_window_height) + GTK_CLIST_CLASS_FW (clist)->resync_selection + (clist, (GdkEvent *) event); + break; - last_button = i + 1; + case GTK_SELECTION_SINGLE: + case GTK_SELECTION_MULTIPLE: + if (get_selection_info (clist, event->x, event->y, &row, &column)) + { + if (clist->anchor == clist->focus_row) + toggle_row (clist, row, column, (GdkEvent *) event); + } + clist->anchor = -1; + break; + + default: + break; + } } - button_allocation.width += (clist->column[last_column].area.width + - 2 * (CELL_SPACING + COLUMN_INSET)); - gtk_widget_size_allocate (clist->column[last_button].button, - &button_allocation); + return FALSE; +} + +static gint +horizontal_timeout (GtkCList *clist) +{ + gint x, y; + GdkEventMotion event; + GdkModifierType mask; + + g_return_val_if_fail (GTK_IS_CLIST (clist), FALSE); + + clist->htimer = 0; + gdk_window_get_pointer (clist->clist_window, &x, &y, &mask); + + event.is_hint = 0; + event.x = x; + event.y = y; + event.state = mask; - if (clist->column[last_button].resizeable) - { - button_allocation.x += button_allocation.width; + gtk_clist_motion (GTK_WIDGET (clist), &event); - gdk_window_show (clist->column[last_button].window); - gdk_window_move_resize (clist->column[last_button].window, - button_allocation.x - (DRAG_WIDTH / 2), - 0, DRAG_WIDTH, clist->column_title_area.height); - } - else - gdk_window_hide (clist->column[last_button].window); + return FALSE; } -static void -size_allocate_columns (GtkCList * clist) +static gint +vertical_timeout (GtkCList *clist) { - gint xoffset = CELL_SPACING + COLUMN_INSET; - gint last_column; - gint width = 0; - gint i; + gint x, y; + GdkEventMotion event; + GdkModifierType mask; - /* find last visible column and calculate correct column width */ - for (last_column = clist->columns - 1; - last_column >= 0 && !clist->column[last_column].visible; last_column--); + g_return_val_if_fail (GTK_IS_CLIST (clist), FALSE); - if (last_column < 0) - return; + clist->vtimer = 0; + gdk_window_get_pointer (clist->clist_window, &x, &y, &mask); - for (i = 0; i < last_column; i++) - { - if (!clist->column[i].visible) - continue; - clist->column[i].area.x = xoffset; - clist->column[i].area.width = clist->column[i].width; - xoffset += clist->column[i].width + CELL_SPACING + (2 * COLUMN_INSET); - } + event.is_hint = 0; + event.x = x; + event.y = y; + event.state = mask; - if (clist->column[i].width_set) - width = clist->column[i].width; - else if (clist->column[i].title) - width = gdk_string_width (GTK_WIDGET (clist)->style->font, - clist->column[i].title); + gtk_clist_motion (GTK_WIDGET (clist), &event); - clist->column[i].area.x = xoffset; - clist->column[i].area.width = MAX (width, - clist->clist_window_width - xoffset - - (CELL_SPACING + COLUMN_INSET)); + return FALSE; } -/* - * SELECTION - * select_row - * real_select_row - * real_unselect_row - * get_selection_info - */ static void -toggle_row (GtkCList * clist, - gint row, - gint column, - GdkEvent * event) +move_vertical (GtkCList *clist, + gint row, + gfloat align) { - GtkCListRow *clist_row; + gint y; + GtkAdjustment *adj; - switch (clist->selection_mode) - { - case GTK_SELECTION_EXTENDED: - case GTK_SELECTION_MULTIPLE: - case GTK_SELECTION_SINGLE: + adj = GTK_RANGE (clist->vscrollbar)->adjustment; - clist_row = g_list_nth (clist->row_list, row)->data; - if (clist_row->state == GTK_STATE_SELECTED) - { - unselect_row (clist, row, column, event); - return; - } + y = ROW_TOP_YPIXEL (clist, row) - clist->voffset; + + y = y - align * (clist->clist_window_height - clist->row_height) + + (2 * align - 1) * CELL_SPACING; + + if (y + adj->page_size > adj->upper) + adj->value = adj->upper - adj->page_size; + else + adj->value = y; - case GTK_SELECTION_BROWSE: - select_row (clist, row, column, event); - break; - } + gtk_signal_emit_by_name (GTK_OBJECT (adj), "value_changed"); } static void -select_row (GtkCList * clist, - gint row, - gint column, - GdkEvent * event) +move_horizontal (GtkCList *clist, + gint diff) { - gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], - row, column, event); -} + gfloat upper; + GtkAdjustment *adj; -static void -unselect_row (GtkCList * clist, - gint row, - gint column, - GdkEvent * event) -{ - gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], - row, column, event); + adj = GTK_RANGE (clist->hscrollbar)->adjustment; + + adj->value += diff; + + upper = adj->upper - adj->page_size; + adj->value = MIN (adj->value, upper); + adj->value = MAX (adj->value, 0.0); + + gtk_signal_emit_by_name (GTK_OBJECT (adj), "value_changed"); } -static void -real_select_row (GtkCList * clist, - gint row, - gint column, - GdkEvent * event) +static gint +gtk_clist_motion (GtkWidget *widget, + GdkEventMotion *event) { - GtkCListRow *clist_row; - GList *list; - gint sel_row; - gboolean row_selected; + GtkCList *clist; + gint x; + gint y; + gint row; + gint new_width; - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE); - if (row < 0 || row > (clist->rows - 1)) - return; + clist = GTK_CLIST (widget); + if (!(gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist))) + return FALSE; - switch (clist->selection_mode) + if (GTK_CLIST_IN_DRAG (clist)) { - case GTK_SELECTION_SINGLE: - case GTK_SELECTION_BROWSE: + if (event->is_hint || event->window != widget->window) + gtk_widget_get_pointer (widget, &x, NULL); + else + x = event->x; + + new_width = new_column_width (clist, clist->drag_pos, &x); + if (x != clist->x_drag) + { + /* x_drag < 0 indicates that the xor line is already invisible */ + if (clist->x_drag >= 0) + draw_xor_line (clist); - row_selected = FALSE; - list = clist->selection; + clist->x_drag = x; - while (list) + if (clist->x_drag >= 0) + draw_xor_line (clist); + } + + if (new_width <= MAX (COLUMN_MIN_WIDTH + 1, + clist->column[clist->drag_pos].min_width + 1)) { - sel_row = GPOINTER_TO_INT (list->data); - list = list->next; + if (COLUMN_LEFT_XPIXEL (clist, clist->drag_pos) < 0 && x < 0) + gtk_clist_moveto (clist, -1, clist->drag_pos, 0, 0); + return FALSE; + } + if (clist->column[clist->drag_pos].max_width >= COLUMN_MIN_WIDTH && + new_width >= clist->column[clist->drag_pos].max_width) + { + if (COLUMN_LEFT_XPIXEL (clist, clist->drag_pos) + new_width > + clist->clist_window_width && x < 0) + move_horizontal (clist, + COLUMN_LEFT_XPIXEL (clist, clist->drag_pos) + + new_width - clist->clist_window_width + + COLUMN_INSET + CELL_SPACING); + return FALSE; + } + } - if (row == sel_row) - row_selected = TRUE; + if (event->is_hint || event->window != clist->clist_window) + gdk_window_get_pointer (clist->clist_window, &x, &y, NULL); + + /* horizontal autoscrolling */ + if (LIST_WIDTH (clist) > clist->clist_window_width && + (x < 0 || x >= clist->clist_window_width)) + { + if (clist->htimer) + return FALSE; + + clist->htimer = gtk_timeout_add + (SCROLL_TIME, (GtkFunction) horizontal_timeout, clist); + + if (!((x < 0 && GTK_RANGE (clist->hscrollbar)->adjustment->value == 0) || + (x >= clist->clist_window_width && + GTK_RANGE (clist->hscrollbar)->adjustment->value == + LIST_WIDTH (clist) - clist->clist_window_width))) + { + if (x < 0) + move_horizontal (clist, -1 + (x/2)); else - gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], - sel_row, column, event); + move_horizontal (clist, 1 + (x - clist->clist_window_width) / 2); } - - if (row_selected) - return; - - default: - break; } - clist_row = (g_list_nth (clist->row_list, row))->data; + if (GTK_CLIST_IN_DRAG (clist)) + return FALSE; - if (clist_row->state != GTK_STATE_NORMAL || !clist_row->selectable) - return; + /* vertical autoscrolling */ + row = ROW_FROM_YPIXEL (clist, y); - clist_row->state = GTK_STATE_SELECTED; - if (!clist->selection) + /* don't scroll on last pixel row if it's a cell spacing */ + if (y == clist->clist_window_height-1 && + y == ROW_TOP_YPIXEL (clist, row-1) + clist->row_height) + return FALSE; + + if (LIST_HEIGHT (clist) > clist->clist_window_height && + (y < 0 || y >= clist->clist_window_height)) { - clist->selection = g_list_append (clist->selection, - GINT_TO_POINTER (row)); - clist->selection_end = clist->selection; + if (clist->vtimer) + return FALSE; + + clist->vtimer = gtk_timeout_add (SCROLL_TIME, + (GtkFunction) vertical_timeout, clist); + + if (GTK_CLIST_DRAG_SELECTION (clist)) + { + if ((y < 0 && clist->focus_row == 0) || + (y >= clist->clist_window_height && + clist->focus_row == clist->rows-1)) + return FALSE; + } + } + + row = CLAMP (row, 0, clist->rows - 1); + + if (GTK_CLIST_DRAG_SELECTION (clist)) + { + if (row == clist->focus_row) + return FALSE; + + gtk_clist_draw_focus (widget); + clist->focus_row = row; + gtk_clist_draw_focus (widget); + + switch (clist->selection_mode) + { + case GTK_SELECTION_BROWSE: + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], + clist->focus_row, -1, event); + break; + case GTK_SELECTION_EXTENDED: + update_extended_selection (clist, clist->focus_row); + break; + default: + break; + } } - else - clist->selection_end = - g_list_append (clist->selection_end, GINT_TO_POINTER (row))->next; - if (!GTK_CLIST_FROZEN (clist) - && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)) - GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row); + if (ROW_TOP_YPIXEL(clist, row) < 0) + move_vertical (clist, row, 0); + else if (ROW_TOP_YPIXEL(clist, row) + clist->row_height > + clist->clist_window_height) + move_vertical (clist, row, 1); + + return FALSE; } static void -real_unselect_row (GtkCList * clist, - gint row, - gint column, - GdkEvent * event) +gtk_clist_size_request (GtkWidget *widget, + GtkRequisition *requisition) { - GtkCListRow *clist_row; + gint i; + GtkCList *clist; - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CLIST (widget)); + g_return_if_fail (requisition != NULL); - if (row < 0 || row > (clist->rows - 1)) - return; + clist = GTK_CLIST (widget); - clist_row = (g_list_nth (clist->row_list, row))->data; + requisition->width = 0; + requisition->height = 0; - if (clist_row->state == GTK_STATE_SELECTED) - { - clist_row->state = GTK_STATE_NORMAL; + /* compute the size of the column title (title) area */ + clist->column_title_area.height = 0; + if (GTK_CLIST_SHOW_TITLES (clist)) + for (i = 0; i < clist->columns; i++) + if (clist->column[i].button) + { + gtk_widget_size_request (clist->column[i].button, + &clist->column[i].button->requisition); + clist->column_title_area.height = + MAX (clist->column_title_area.height, + clist->column[i].button->requisition.height); + } + requisition->height += clist->column_title_area.height; - if (clist->selection_end && - clist->selection_end->data == GINT_TO_POINTER (row)) - clist->selection_end = clist->selection_end->prev; + /* add the vscrollbar space */ + if ((clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC) || + GTK_WIDGET_VISIBLE (clist->vscrollbar)) + { + gtk_widget_size_request (clist->vscrollbar, + &clist->vscrollbar->requisition); - clist->selection = g_list_remove (clist->selection, - GINT_TO_POINTER (row)); - - if (!GTK_CLIST_FROZEN (clist) - && (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)) - GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row); + requisition->width += (clist->vscrollbar->requisition.width + + SCROLLBAR_SPACING (clist)); + requisition->height = MAX (requisition->height, + clist->vscrollbar->requisition.height); } -} - -static gint -get_selection_info (GtkCList * clist, - gint x, - gint y, - gint * row, - gint * column) -{ - gint trow, tcol; - - g_return_val_if_fail (clist != NULL, 0); - g_return_val_if_fail (GTK_IS_CLIST (clist), 0); - - /* bounds checking, return false if the user clicked - * on a blank area */ - trow = ROW_FROM_YPIXEL (clist, y); - if (trow >= clist->rows) - return 0; - - if (row) - *row = trow; - tcol = COLUMN_FROM_XPIXEL (clist, x); - if (tcol >= clist->columns) - return 0; + /* add the hscrollbar space */ + if ((clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC) || + GTK_WIDGET_VISIBLE (clist->hscrollbar)) + { + gtk_widget_size_request (clist->hscrollbar, + &clist->hscrollbar->requisition); - if (column) - *column = tcol; + requisition->height += (clist->hscrollbar->requisition.height + + SCROLLBAR_SPACING (clist)); + requisition->width = MAX (clist->hscrollbar->requisition.width, + requisition->width - + clist->vscrollbar->requisition.width); - return 1; -} + } -gint -gtk_clist_get_selection_info (GtkCList *clist, - gint x, - gint y, - gint * row, - gint * column) -{ - g_return_val_if_fail (clist != NULL, 0); - g_return_val_if_fail (GTK_IS_CLIST (clist), 0); - return get_selection_info (clist, x, y, row, column); + requisition->width += (widget->style->klass->xthickness + + GTK_CONTAINER (widget)->border_width) * 2; + requisition->height += (widget->style->klass->ythickness + + GTK_CONTAINER (widget)->border_width) * 2; } -/* - * RESIZE COLUMNS - * draw_xor_line - * new_column_width - * resize_column - */ -static void -draw_xor_line (GtkCList * clist) +static void +gtk_clist_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) { - GtkWidget *widget; - - g_return_if_fail (clist != NULL); - - widget = GTK_WIDGET (clist); + GtkCList *clist; + GtkAllocation clist_allocation; + GtkAllocation child_allocation; + gint i, vscrollbar_vis, hscrollbar_vis; + gint border_width; - gdk_draw_line (widget->window, clist->xor_gc, - clist->x_drag, - widget->style->klass->ythickness, - clist->x_drag, - clist->column_title_area.height + - clist->clist_window_height + 1); -} + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CLIST (widget)); + g_return_if_fail (allocation != NULL); -/* this function returns the new width of the column being resized given - * the column and x position of the cursor; the x cursor position is passed - * in as a pointer and automagicly corrected if it's beyond min/max limits */ -static gint -new_column_width (GtkCList *clist, - gint column, - gint *x) -{ - gint xthickness = GTK_WIDGET (clist)->style->klass->xthickness; - gint width; - gint cx; - gint dx; + clist = GTK_CLIST (widget); + widget->allocation = *allocation; + border_width = GTK_CONTAINER (widget)->border_width; - /* first translate the x position from widget->window - * to clist->clist_window */ - cx = *x - xthickness; + if (GTK_WIDGET_REALIZED (widget)) + { + gdk_window_move_resize (widget->window, + allocation->x + border_width, + allocation->y + border_width, + allocation->width - border_width * 2, + allocation->height - border_width * 2); + } - /* calculate new column width making sure it doesn't end up - * less than the minimum width */ - dx = (COLUMN_LEFT_XPIXEL (clist, column) + COLUMN_INSET + - (column < clist->columns - 1) * CELL_SPACING); - width = cx - dx; + /* use internal allocation structure for all the math + * because it's easier than always subtracting the container + * border width */ + clist->internal_allocation.x = 0; + clist->internal_allocation.y = 0; + clist->internal_allocation.width = MAX (1, allocation->width - + border_width * 2); + clist->internal_allocation.height = MAX (1, allocation->height - + border_width * 2); + + /* allocate clist window assuming no scrollbars */ + clist_allocation.x = (clist->internal_allocation.x + + widget->style->klass->xthickness); + clist_allocation.y = (clist->internal_allocation.y + + widget->style->klass->ythickness + + clist->column_title_area.height); + clist_allocation.width = MAX (1, clist->internal_allocation.width - + (2 * widget->style->klass->xthickness)); + clist_allocation.height = MAX (1, clist->internal_allocation.height - + (2 * widget->style->klass->ythickness) - + clist->column_title_area.height); + + /* + * here's where we decide to show/not show the scrollbars + */ + vscrollbar_vis = 0; + hscrollbar_vis = 0; + + for (i = 0; i <= 1; i++) + { + if (LIST_HEIGHT (clist) <= clist_allocation.height && + clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC) + { + vscrollbar_vis = 0; + } + else if (!vscrollbar_vis) + { + vscrollbar_vis = 1; + clist_allocation.width = MAX (1, clist_allocation.width - + (clist->vscrollbar->requisition.width + + SCROLLBAR_SPACING (clist))); + } + + if (LIST_WIDTH (clist) <= clist_allocation.width && + clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC) + { + hscrollbar_vis = 0; + } + else if (!hscrollbar_vis) + { + hscrollbar_vis = 1; + clist_allocation.height = MAX (1, clist_allocation.height - + (clist->hscrollbar->requisition.height + + SCROLLBAR_SPACING (clist))); + } + } + + clist->clist_window_width = clist_allocation.width; + clist->clist_window_height = clist_allocation.height; + + if (GTK_WIDGET_REALIZED (widget)) + { + gdk_window_move_resize (clist->clist_window, + clist_allocation.x, + clist_allocation.y, + clist_allocation.width, + clist_allocation.height); + } + + /* position the window which holds the column title buttons */ + clist->column_title_area.x = widget->style->klass->xthickness; + clist->column_title_area.y = widget->style->klass->ythickness; + clist->column_title_area.width = clist_allocation.width; + + if (GTK_WIDGET_REALIZED (widget)) + { + gdk_window_move_resize (clist->title_window, + clist->column_title_area.x, + clist->column_title_area.y, + clist->column_title_area.width, + clist->column_title_area.height); + } + + /* column button allocation */ + size_allocate_columns (clist); + size_allocate_title_buttons (clist); - if (width < MAX (COLUMN_MIN_WIDTH, clist->column[column].min_width)) + adjust_scrollbars (clist); + + /* allocate the vscrollbar */ + if (vscrollbar_vis) { - width = MAX (COLUMN_MIN_WIDTH, clist->column[column].min_width); - cx = dx + width; - *x = cx + xthickness; + if (!GTK_WIDGET_VISIBLE (clist->vscrollbar)) + gtk_widget_show (clist->vscrollbar); + + child_allocation.x = (clist->internal_allocation.x + + clist->internal_allocation.width - + clist->vscrollbar->requisition.width); + child_allocation.y = clist->internal_allocation.y; + child_allocation.width = clist->vscrollbar->requisition.width; + child_allocation.height = MAX (1, clist->internal_allocation.height - + (hscrollbar_vis ? + (clist->hscrollbar->requisition.height + + SCROLLBAR_SPACING (clist)) : 0)); + gtk_widget_size_allocate (clist->vscrollbar, &child_allocation); } - else if (clist->column[column].max_width >= COLUMN_MIN_WIDTH && - width > clist->column[column].max_width) + else { - width = clist->column[column].max_width; - cx = dx + clist->column[column].max_width; - *x = cx + xthickness; - } - - if (cx < 0 || cx > clist->clist_window_width) - *x = -1; - - return width; -} - -/* this will do more later */ -static void -resize_column (GtkCList * clist, - gint column, - gint width) -{ - gtk_clist_set_column_width (clist, column, width); -} - -/* BUTTONS */ -static void -column_button_create (GtkCList * clist, - gint column) -{ - GtkWidget *button; - - button = clist->column[column].button = gtk_button_new (); - if (GTK_WIDGET_REALIZED (clist) && clist->title_window) - gtk_widget_set_parent_window (clist->column[column].button, clist->title_window); - gtk_widget_set_parent (button, GTK_WIDGET (clist)); + if (GTK_WIDGET_VISIBLE (clist->vscrollbar)) + gtk_widget_hide (clist->vscrollbar); + } - gtk_signal_connect (GTK_OBJECT (button), "clicked", - (GtkSignalFunc) column_button_clicked, - (gpointer) clist); + if (hscrollbar_vis) + { + if (!GTK_WIDGET_VISIBLE (clist->hscrollbar)) + gtk_widget_show (clist->hscrollbar); + + child_allocation.x = clist->internal_allocation.x; + child_allocation.y = (clist->internal_allocation.y + + clist->internal_allocation.height - + clist->hscrollbar->requisition.height); + child_allocation.width = MAX (1, clist->internal_allocation.width - + (vscrollbar_vis ? + (clist->vscrollbar->requisition.width + + SCROLLBAR_SPACING (clist)) : 0)); + child_allocation.height = clist->hscrollbar->requisition.height; + + gtk_widget_size_allocate (clist->hscrollbar, &child_allocation); + } + else + { + if (GTK_WIDGET_VISIBLE (clist->hscrollbar)) + gtk_widget_hide (clist->hscrollbar); + } - gtk_widget_show (button); + /* set the vscrollbar adjustments */ + adjust_scrollbars (clist); } +/* GTKCONTAINER + * gtk_clist_forall + */ static void -column_button_clicked (GtkWidget * widget, - gpointer data) +gtk_clist_forall (GtkContainer *container, + gboolean include_internals, + GtkCallback callback, + gpointer callback_data) { - gint i; GtkCList *clist; - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_CLIST (data)); - - clist = GTK_CLIST (data); - - /* find the column who's button was pressed */ - for (i = 0; i < clist->columns; i++) - if (clist->column[i].button == widget) - break; + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_CLIST (container)); + g_return_if_fail (callback != NULL); - gtk_signal_emit (GTK_OBJECT (clist), clist_signals[CLICK_COLUMN], i); + clist = GTK_CLIST (container); + + if (include_internals) + { + guint i; + + /* callback for the column buttons */ + for (i = 0; i < clist->columns; i++) + if (clist->column[i].button) + (*callback) (clist->column[i].button, callback_data); + + /* callbacks for the scrollbars */ + if (clist->vscrollbar) + (*callback) (clist->vscrollbar, callback_data); + if (clist->hscrollbar) + (*callback) (clist->hscrollbar, callback_data); + } } -/* - * SCROLLBARS - * - * functions: - * create_scrollbars - * adjust_scrollbars - * vadjustment_changed - * hadjustment_changed - * vadjustment_value_changed - * hadjustment_value_changed +/* PRIVATE DRAWING FUNCTIONS + * get_cell_style + * draw_cell_pixmap + * draw_row + * draw_rows + * draw_xor_line */ static void -create_scrollbars (GtkCList * clist) -{ - GtkAdjustment *adjustment; - - clist->vscrollbar = gtk_vscrollbar_new (NULL); - - adjustment = gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar)); - - gtk_signal_connect (GTK_OBJECT (adjustment), "changed", - (GtkSignalFunc) vadjustment_changed, - (gpointer) clist); - - gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed", - (GtkSignalFunc) vadjustment_value_changed, - (gpointer) clist); - - gtk_widget_set_parent (clist->vscrollbar, GTK_WIDGET (clist)); - gtk_widget_show (clist->vscrollbar); - - clist->hscrollbar = gtk_hscrollbar_new (NULL); - - adjustment = gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar)); - - gtk_signal_connect (GTK_OBJECT (adjustment), "changed", - (GtkSignalFunc) hadjustment_changed, - (gpointer) clist); - - gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed", - (GtkSignalFunc) hadjustment_value_changed, - (gpointer) clist); - - gtk_widget_set_parent (clist->hscrollbar, GTK_WIDGET (clist)); - gtk_widget_show (clist->hscrollbar); -} - -static void -adjust_scrollbars (GtkCList * clist) +get_cell_style (GtkCList *clist, + GtkCListRow *clist_row, + gint state, + gint column, + GtkStyle **style, + GdkGC **fg_gc, + GdkGC **bg_gc) { - GTK_RANGE (clist->vscrollbar)->adjustment->page_size = clist->clist_window_height; - GTK_RANGE (clist->vscrollbar)->adjustment->page_increment = clist->clist_window_height / 2; - GTK_RANGE (clist->vscrollbar)->adjustment->step_increment = 10; - GTK_RANGE (clist->vscrollbar)->adjustment->lower = 0; - GTK_RANGE (clist->vscrollbar)->adjustment->upper = LIST_HEIGHT (clist); - - if (clist->clist_window_height - clist->voffset > LIST_HEIGHT (clist)) + if (clist_row->cell[column].style) { - GTK_RANGE (clist->vscrollbar)->adjustment->value = MAX (0, LIST_HEIGHT (clist) - - clist->clist_window_height); - gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment), - "value_changed"); + if (style) + *style = clist_row->cell[column].style; + if (fg_gc) + *fg_gc = clist_row->cell[column].style->fg_gc[state]; + if (bg_gc) + *bg_gc = clist_row->cell[column].style->bg_gc[state]; } - - GTK_RANGE (clist->hscrollbar)->adjustment->page_size = clist->clist_window_width; - GTK_RANGE (clist->hscrollbar)->adjustment->page_increment = clist->clist_window_width / 2; - GTK_RANGE (clist->hscrollbar)->adjustment->step_increment = 10; - GTK_RANGE (clist->hscrollbar)->adjustment->lower = 0; - GTK_RANGE (clist->hscrollbar)->adjustment->upper = LIST_WIDTH (clist); - - if (clist->clist_window_width - clist->hoffset > LIST_WIDTH (clist)) + else if (clist_row->style) { - GTK_RANGE (clist->hscrollbar)->adjustment->value = MAX (0, LIST_WIDTH (clist) - - clist->clist_window_width); - gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->hscrollbar)->adjustment), - "value_changed"); + if (style) + *style = clist_row->style; + if (fg_gc) + *fg_gc = clist_row->style->fg_gc[state]; + if (bg_gc) + *bg_gc = clist_row->style->bg_gc[state]; } - - if (LIST_HEIGHT (clist) <= clist->clist_window_height && - clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC) + else { - if (GTK_WIDGET_VISIBLE (clist->vscrollbar)) + if (style) + *style = GTK_WIDGET (clist)->style; + if (fg_gc) + *fg_gc = GTK_WIDGET (clist)->style->fg_gc[state]; + if (bg_gc) + *bg_gc = GTK_WIDGET (clist)->style->bg_gc[state]; + + if (state != GTK_STATE_SELECTED) { - gtk_widget_hide (clist->vscrollbar); - gtk_widget_size_allocate (GTK_WIDGET (clist), - >K_WIDGET (clist)->allocation); + if (fg_gc && clist_row->fg_set) + *fg_gc = clist->fg_gc; + if (bg_gc && clist_row->bg_set) + *bg_gc = clist->bg_gc; } } - else +} + +static gint +draw_cell_pixmap (GdkWindow *window, + GdkRectangle *clip_rectangle, + GdkGC *fg_gc, + GdkPixmap *pixmap, + GdkBitmap *mask, + gint x, + gint y, + gint width, + gint height) +{ + gint xsrc = 0; + gint ysrc = 0; + + if (mask) { - if (!GTK_WIDGET_VISIBLE (clist->vscrollbar)) - { - gtk_widget_show (clist->vscrollbar); - gtk_widget_size_allocate (GTK_WIDGET (clist), - >K_WIDGET (clist)->allocation); - } + gdk_gc_set_clip_mask (fg_gc, mask); + gdk_gc_set_clip_origin (fg_gc, x, y); } - if (LIST_WIDTH (clist) <= clist->clist_window_width && - clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC) + if (x < clip_rectangle->x) { - if (GTK_WIDGET_VISIBLE (clist->hscrollbar)) - { - gtk_widget_hide (clist->hscrollbar); - gtk_widget_size_allocate (GTK_WIDGET (clist), - >K_WIDGET (clist)->allocation); - } + xsrc = clip_rectangle->x - x; + width -= xsrc; + x = clip_rectangle->x; } - else + if (x + width > clip_rectangle->x + clip_rectangle->width) + width = clip_rectangle->x + clip_rectangle->width - x; + + if (y < clip_rectangle->y) { - if (!GTK_WIDGET_VISIBLE (clist->hscrollbar)) - { - gtk_widget_show (clist->hscrollbar); - gtk_widget_size_allocate (GTK_WIDGET (clist), - >K_WIDGET (clist)->allocation); - } + ysrc = clip_rectangle->y - y; + height -= ysrc; + y = clip_rectangle->y; } + if (y + height > clip_rectangle->y + clip_rectangle->height) + height = clip_rectangle->y + clip_rectangle->height - y; - gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->vscrollbar)->adjustment), "changed"); - gtk_signal_emit_by_name (GTK_OBJECT (GTK_RANGE (clist->hscrollbar)->adjustment), "changed"); + gdk_draw_pixmap (window, fg_gc, pixmap, xsrc, ysrc, x, y, width, height); + gdk_gc_set_clip_origin (fg_gc, 0, 0); + + return x + MAX (width, 0); } static void -vadjustment_changed (GtkAdjustment * adjustment, - gpointer data) +draw_row (GtkCList *clist, + GdkRectangle *area, + gint row, + GtkCListRow *clist_row) { - GtkCList *clist; + GtkWidget *widget; + GdkRectangle *rect; + GdkRectangle row_rectangle; + GdkRectangle cell_rectangle; + GdkRectangle clip_rectangle; + GdkRectangle intersect_rectangle; + gint state; + gint i; - g_return_if_fail (adjustment != NULL); - g_return_if_fail (data != NULL); + g_return_if_fail (clist != NULL); - clist = GTK_CLIST (data); -} + /* bail now if we arn't drawable yet */ + if (!GTK_WIDGET_DRAWABLE (clist) || row < 0 || row >= clist->rows) + return; -static void -hadjustment_changed (GtkAdjustment * adjustment, - gpointer data) -{ - GtkCList *clist; + widget = GTK_WIDGET (clist); - g_return_if_fail (adjustment != NULL); - g_return_if_fail (data != NULL); + /* if the function is passed the pointer to the row instead of null, + * it avoids this expensive lookup */ + if (!clist_row) + clist_row = (g_list_nth (clist->row_list, row))->data; - clist = GTK_CLIST (data); -} + /* rectangle of the entire row */ + row_rectangle.x = 0; + row_rectangle.y = ROW_TOP_YPIXEL (clist, row); + row_rectangle.width = clist->clist_window_width; + row_rectangle.height = clist->row_height; -static void -check_exposures (GtkCList *clist) -{ - GdkEvent *event; + /* rectangle of the cell spacing above the row */ + cell_rectangle.x = 0; + cell_rectangle.y = row_rectangle.y - CELL_SPACING; + cell_rectangle.width = row_rectangle.width; + cell_rectangle.height = CELL_SPACING; - if (!GTK_WIDGET_REALIZED (clist)) - return; + /* rectangle used to clip drawing operations, it's y and height + * positions only need to be set once, so we set them once here. + * the x and width are set withing the drawing loop below once per + * column */ + clip_rectangle.y = row_rectangle.y; + clip_rectangle.height = row_rectangle.height; - /* Make sure graphics expose events are processed before scrolling - * again */ - while ((event = gdk_event_get_graphics_expose (clist->clist_window)) != NULL) + if (clist_row->state == GTK_STATE_NORMAL) { - gtk_widget_event (GTK_WIDGET (clist), event); - if (event->expose.count == 0) + state = GTK_STATE_PRELIGHT; + if (clist_row->fg_set) + gdk_gc_set_foreground (clist->fg_gc, &clist_row->foreground); + if (clist_row->bg_set) + gdk_gc_set_foreground (clist->bg_gc, &clist_row->background); + } + else + state = clist_row->state; + + /* draw the cell borders and background */ + if (area) + { + rect = &intersect_rectangle; + if (gdk_rectangle_intersect (area, &cell_rectangle, + &intersect_rectangle)) + gdk_draw_rectangle (clist->clist_window, + widget->style->base_gc[GTK_STATE_NORMAL], + TRUE, + intersect_rectangle.x, + intersect_rectangle.y, + intersect_rectangle.width, + intersect_rectangle.height); + + /* the last row has to clear it's bottom cell spacing too */ + if (clist_row == clist->row_list_end->data) { - gdk_event_free (event); - break; + cell_rectangle.y += clist->row_height + CELL_SPACING; + + if (gdk_rectangle_intersect (area, &cell_rectangle, + &intersect_rectangle)) + gdk_draw_rectangle (clist->clist_window, + widget->style->base_gc[GTK_STATE_NORMAL], + TRUE, + intersect_rectangle.x, + intersect_rectangle.y, + intersect_rectangle.width, + intersect_rectangle.height); } - gdk_event_free (event); + + if (!gdk_rectangle_intersect (area, &row_rectangle,&intersect_rectangle)) + return; + } -} + else + { + rect = &clip_rectangle; + gdk_draw_rectangle (clist->clist_window, + widget->style->base_gc[GTK_STATE_NORMAL], + TRUE, + cell_rectangle.x, + cell_rectangle.y, + cell_rectangle.width, + cell_rectangle.height); -static void -vadjustment_value_changed (GtkAdjustment * adjustment, - gpointer data) -{ - GtkCList *clist; - GdkRectangle area; - gint diff, value; + /* the last row has to clear it's bottom cell spacing too */ + if (clist_row == clist->row_list_end->data) + { + cell_rectangle.y += clist->row_height + CELL_SPACING; - g_return_if_fail (adjustment != NULL); - g_return_if_fail (data != NULL); - g_return_if_fail (GTK_IS_CLIST (data)); + gdk_draw_rectangle (clist->clist_window, + widget->style->base_gc[GTK_STATE_NORMAL], + TRUE, + cell_rectangle.x, + cell_rectangle.y, + cell_rectangle.width, + cell_rectangle.height); + } + } + + /* iterate and draw all the columns (row cells) and draw their contents */ + for (i = 0; i < clist->columns; i++) + { + GtkStyle *style; + GdkGC *fg_gc; + GdkGC *bg_gc; - clist = GTK_CLIST (data); + gint width; + gint height; + gint pixmap_width; + gint offset = 0; + gint row_center_offset; - if (!GTK_WIDGET_DRAWABLE (clist)) - return; + if (!clist->column[i].visible) + continue; - value = adjustment->value; + get_cell_style (clist, clist_row, state, i, &style, &fg_gc, &bg_gc); - if (adjustment == gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar))) - { - if (value > -clist->voffset) - { - /* scroll down */ - diff = value + clist->voffset; + clip_rectangle.x = clist->column[i].area.x + clist->hoffset; + clip_rectangle.width = clist->column[i].area.width; - /* we have to re-draw the whole screen here... */ - if (diff >= clist->clist_window_height) - { - clist->voffset = -value; - draw_rows (clist, NULL); - return; - } + /* calculate clipping region clipping region */ + clip_rectangle.x -= COLUMN_INSET + CELL_SPACING; + clip_rectangle.width += (2 * COLUMN_INSET + CELL_SPACING + + (i + 1 == clist->columns) * CELL_SPACING); + + if (area && !gdk_rectangle_intersect (area, &clip_rectangle, + &intersect_rectangle)) + continue; - if ((diff != 0) && (diff != clist->clist_window_height)) - gdk_window_copy_area (clist->clist_window, - clist->fg_gc, - 0, 0, - clist->clist_window, - 0, - diff, - clist->clist_window_width, - clist->clist_window_height - diff); + gdk_draw_rectangle (clist->clist_window, bg_gc, TRUE, + rect->x, rect->y, rect->width, rect->height); - area.x = 0; - area.y = clist->clist_window_height - diff; - area.width = clist->clist_window_width; - area.height = diff; - } - else - { - /* scroll up */ - diff = -clist->voffset - value; + clip_rectangle.x += COLUMN_INSET + CELL_SPACING; + clip_rectangle.width -= (2 * COLUMN_INSET + CELL_SPACING + + (i + 1 == clist->columns) * CELL_SPACING); - /* we have to re-draw the whole screen here... */ - if (diff >= clist->clist_window_height) - { - clist->voffset = -value; - draw_rows (clist, NULL); - return; - } + /* calculate real width for column justification */ + pixmap_width = 0; + offset = 0; + switch (clist_row->cell[i].type) + { + case GTK_CELL_TEXT: + width = gdk_string_width (style->font, + GTK_CELL_TEXT (clist_row->cell[i])->text); + break; + case GTK_CELL_PIXMAP: + gdk_window_get_size (GTK_CELL_PIXMAP (clist_row->cell[i])->pixmap, + &pixmap_width, &height); + width = pixmap_width; + break; + case GTK_CELL_PIXTEXT: + gdk_window_get_size (GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap, + &pixmap_width, &height); + width = (pixmap_width + + GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing + + gdk_string_width (style->font, + GTK_CELL_PIXTEXT + (clist_row->cell[i])->text)); + break; + default: + continue; + break; + } - if ((diff != 0) && (diff != clist->clist_window_height)) - gdk_window_copy_area (clist->clist_window, - clist->fg_gc, - 0, diff, - clist->clist_window, - 0, - 0, - clist->clist_window_width, - clist->clist_window_height - diff); + switch (clist->column[i].justification) + { + case GTK_JUSTIFY_LEFT: + offset = clip_rectangle.x + clist_row->cell[i].horizontal; + break; + case GTK_JUSTIFY_RIGHT: + offset = (clip_rectangle.x + clist_row->cell[i].horizontal + + clip_rectangle.width - width); + break; + case GTK_JUSTIFY_CENTER: + case GTK_JUSTIFY_FILL: + offset = (clip_rectangle.x + clist_row->cell[i].horizontal + + (clip_rectangle.width / 2) - (width / 2)); + break; + }; - area.x = 0; - area.y = 0; - area.width = clist->clist_window_width; - area.height = diff; + /* Draw Text and/or Pixmap */ + switch (clist_row->cell[i].type) + { + case GTK_CELL_PIXMAP: + draw_cell_pixmap (clist->clist_window, &clip_rectangle, fg_gc, + GTK_CELL_PIXMAP (clist_row->cell[i])->pixmap, + GTK_CELL_PIXMAP (clist_row->cell[i])->mask, + offset, + clip_rectangle.y + clist_row->cell[i].vertical + + (clip_rectangle.height - height) / 2, + pixmap_width, height); + break; + case GTK_CELL_PIXTEXT: + offset = + draw_cell_pixmap (clist->clist_window, &clip_rectangle, fg_gc, + GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap, + GTK_CELL_PIXTEXT (clist_row->cell[i])->mask, + offset, + clip_rectangle.y + clist_row->cell[i].vertical+ + (clip_rectangle.height - height) / 2, + pixmap_width, height); + offset += GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing; + case GTK_CELL_TEXT: + if (style != GTK_WIDGET (clist)->style) + row_center_offset = (((clist->row_height - style->font->ascent - + style->font->descent - 1) / 2) + 1.5 + + style->font->ascent); + else + row_center_offset = clist->row_center_offset; + gdk_gc_set_clip_rectangle (fg_gc, &clip_rectangle); + gdk_draw_string (clist->clist_window, style->font, fg_gc, + offset, + row_rectangle.y + row_center_offset + + clist_row->cell[i].vertical, + (clist_row->cell[i].type == GTK_CELL_PIXTEXT) ? + GTK_CELL_PIXTEXT (clist_row->cell[i])->text : + GTK_CELL_TEXT (clist_row->cell[i])->text); + gdk_gc_set_clip_rectangle (fg_gc, NULL); + break; + default: + break; } - - clist->voffset = -value; - if ((diff != 0) && (diff != clist->clist_window_height)) - check_exposures (clist); } - draw_rows (clist, &area); + /* draw focus rectangle */ + if (clist->focus_row == row && GTK_WIDGET_HAS_FOCUS (widget)) + { + if (!area) + gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, + row_rectangle.x, row_rectangle.y, + row_rectangle.width - 1, row_rectangle.height - 1); + else if (gdk_rectangle_intersect (area, &row_rectangle, + &intersect_rectangle)) + { + gdk_gc_set_clip_rectangle (clist->xor_gc, &intersect_rectangle); + gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, + row_rectangle.x, row_rectangle.y, + row_rectangle.width - 1, + row_rectangle.height - 1); + gdk_gc_set_clip_rectangle (clist->xor_gc, NULL); + } + } } static void -hadjustment_value_changed (GtkAdjustment * adjustment, - gpointer data) +draw_rows (GtkCList *clist, + GdkRectangle *area) { - GtkCList *clist; - GdkRectangle area; + GList *list; + GtkCListRow *clist_row; gint i; - gint y = 0; - gint diff = 0; - gint value; - - g_return_if_fail (adjustment != NULL); - g_return_if_fail (data != NULL); - g_return_if_fail (GTK_IS_CLIST (data)); + gint first_row; + gint last_row; - clist = GTK_CLIST (data); + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); - if (!GTK_WIDGET_DRAWABLE (clist) || - adjustment != gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar))) + if (clist->row_height == 0 || + !GTK_WIDGET_DRAWABLE (clist)) return; - value = adjustment->value; - - /* move the column buttons and resize windows */ - for (i = 0; i < clist->columns; i++) - { - if (clist->column[i].button) - { - clist->column[i].button->allocation.x -= value + clist->hoffset; - - if (clist->column[i].button->window) - { - gdk_window_move (clist->column[i].button->window, - clist->column[i].button->allocation.x, - clist->column[i].button->allocation.y); - - if (clist->column[i].window) - gdk_window_move (clist->column[i].window, - clist->column[i].button->allocation.x + - clist->column[i].button->allocation.width - - (DRAG_WIDTH / 2), 0); - } - } - } - - if (value > -clist->hoffset) + if (area) { - /* scroll right */ - diff = value + clist->hoffset; - - clist->hoffset = -value; - - /* we have to re-draw the whole screen here... */ - if (diff >= clist->clist_window_width) - { - draw_rows (clist, NULL); - return; - } - - if (GTK_WIDGET_HAS_FOCUS (clist) && !GTK_CLIST_CHILD_HAS_FOCUS (clist) && - GTK_CLIST_ADD_MODE (clist)) - { - y = ROW_TOP_YPIXEL (clist, clist->focus_row); - - gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, 0, y, - clist->clist_window_width - 1, - clist->row_height - 1); - } - gdk_window_copy_area (clist->clist_window, - clist->fg_gc, - 0, 0, - clist->clist_window, - diff, - 0, - clist->clist_window_width - diff, - clist->clist_window_height); - - area.x = clist->clist_window_width - diff; + first_row = ROW_FROM_YPIXEL (clist, area->y); + last_row = ROW_FROM_YPIXEL (clist, area->y + area->height); } else { - /* scroll left */ - if (!(diff = -clist->hoffset - value)) - return; - - clist->hoffset = -value; - - /* we have to re-draw the whole screen here... */ - if (diff >= clist->clist_window_width) - { - draw_rows (clist, NULL); - return; - } - - if (GTK_WIDGET_HAS_FOCUS (clist) && !GTK_CLIST_CHILD_HAS_FOCUS (clist) && - GTK_CLIST_ADD_MODE (clist)) - { - y = ROW_TOP_YPIXEL (clist, clist->focus_row); - - gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, 0, y, - clist->clist_window_width - 1, - clist->row_height - 1); - } - - gdk_window_copy_area (clist->clist_window, - clist->fg_gc, - diff, 0, - clist->clist_window, - 0, - 0, - clist->clist_window_width - diff, - clist->clist_window_height); - - area.x = 0; + first_row = ROW_FROM_YPIXEL (clist, 0); + last_row = ROW_FROM_YPIXEL (clist, clist->clist_window_height); } - area.y = 0; - area.width = diff; - area.height = clist->clist_window_height; - - check_exposures (clist); + /* this is a small special case which exposes the bottom cell line + * on the last row -- it might go away if I change the wall the cell + * spacings are drawn + */ + if (clist->rows == first_row) + first_row--; - if (GTK_WIDGET_HAS_FOCUS (clist) && !GTK_CLIST_CHILD_HAS_FOCUS (clist)) + list = g_list_nth (clist->row_list, first_row); + i = first_row; + while (list) { - if (GTK_CLIST_ADD_MODE (clist)) - { - gint focus_row; - - focus_row = clist->focus_row; - clist->focus_row = -1; - draw_rows (clist, &area); - clist->focus_row = focus_row; - - gdk_draw_rectangle (clist->clist_window, clist->xor_gc, - FALSE, 0, y, clist->clist_window_width - 1, - clist->row_height - 1); - return; - } - else - { - gint x0; - gint x1; - - if (area.x == 0) - { - x0 = clist->clist_window_width - 1; - x1 = diff; - } - else - { - x0 = 0; - x1 = area.x - 1; - } - - y = ROW_TOP_YPIXEL (clist, clist->focus_row); - gdk_draw_line (clist->clist_window, clist->xor_gc, - x0, y + 1, x0, y + clist->row_height - 2); - gdk_draw_line (clist->clist_window, clist->xor_gc, - x1, y + 1, x1, y + clist->row_height - 2); - - } - } - draw_rows (clist, &area); -} - -/* - * Memory Allocation/Distruction Routines for GtkCList stuctures - * - * functions: - * columns_new - * column_title_new - * columns_delete - * row_new - * row_delete - * set_cell_contents - */ -static GtkCListColumn * -columns_new (GtkCList * clist) -{ - gint i; - GtkCListColumn *column; + clist_row = list->data; + list = list->next; - column = g_new (GtkCListColumn, clist->columns); + if (i > last_row) + return; - for (i = 0; i < clist->columns; i++) - { - column[i].area.x = 0; - column[i].area.y = 0; - column[i].area.width = 0; - column[i].area.height = 0; - column[i].title = NULL; - column[i].button = NULL; - column[i].window = NULL; - column[i].width = 0; - column[i].min_width = -1; - column[i].max_width = -1; - column[i].visible = TRUE; - column[i].width_set = FALSE; - column[i].resizeable = TRUE; - column[i].justification = GTK_JUSTIFY_LEFT; + GTK_CLIST_CLASS_FW (clist)->draw_row (clist, area, i, clist_row); + i++; } - return column; + if (!area) + gdk_window_clear_area (clist->clist_window, + 0, ROW_TOP_YPIXEL (clist, i), -1, -1); } -static void -column_title_new (GtkCList *clist, - gint column, - const gchar *title) +static void +draw_xor_line (GtkCList *clist) { - if (clist->column[column].title) - g_free (clist->column[column].title); + GtkWidget *widget; - clist->column[column].title = g_strdup (title); -} + g_return_if_fail (clist != NULL); -static void -columns_delete (GtkCList * clist) -{ - gint i; + widget = GTK_WIDGET (clist); - for (i = 0; i < clist->columns; i++) - if (clist->column[i].title) - g_free (clist->column[i].title); - - g_free (clist->column); + gdk_draw_line (widget->window, clist->xor_gc, + clist->x_drag, + widget->style->klass->ythickness, + clist->x_drag, + clist->column_title_area.height + + clist->clist_window_height + 1); } -static GtkCListRow * -row_new (GtkCList * clist) +/* get cell from coordinates + * get_selection_info + * gtk_clist_get_selection_info + */ +static gint +get_selection_info (GtkCList *clist, + gint x, + gint y, + gint *row, + gint *column) { - int i; - GtkCListRow *clist_row; + gint trow, tcol; - clist_row = g_chunk_new (GtkCListRow, clist->row_mem_chunk); - clist_row->cell = g_chunk_new (GtkCell, clist->cell_mem_chunk); + g_return_val_if_fail (clist != NULL, 0); + g_return_val_if_fail (GTK_IS_CLIST (clist), 0); - for (i = 0; i < clist->columns; i++) - { - clist_row->cell[i].type = GTK_CELL_EMPTY; - clist_row->cell[i].vertical = 0; - clist_row->cell[i].horizontal = 0; - clist_row->cell[i].style = NULL; - } + /* bounds checking, return false if the user clicked + * on a blank area */ + trow = ROW_FROM_YPIXEL (clist, y); + if (trow >= clist->rows) + return 0; - clist_row->fg_set = FALSE; - clist_row->bg_set = FALSE; - clist_row->style = NULL; - clist_row->selectable = TRUE; - clist_row->state = GTK_STATE_NORMAL; - clist_row->data = NULL; - clist_row->destroy = NULL; + if (row) + *row = trow; - return clist_row; + tcol = COLUMN_FROM_XPIXEL (clist, x); + if (tcol >= clist->columns) + return 0; + + if (column) + *column = tcol; + + return 1; +} + +gint +gtk_clist_get_selection_info (GtkCList *clist, + gint x, + gint y, + gint *row, + gint *column) +{ + g_return_val_if_fail (clist != NULL, 0); + g_return_val_if_fail (GTK_IS_CLIST (clist), 0); + return get_selection_info (clist, x, y, row, column); } +/* + * SCROLLBARS + * + * functions: + * create_scrollbars + * adjust_scrollbars + * vadjustment_changed + * hadjustment_changed + * vadjustment_value_changed + * hadjustment_value_changed + * check_exposures + */ static void -row_delete (GtkCList * clist, - GtkCListRow * clist_row) +create_scrollbars (GtkCList *clist) { - gint i; + GtkAdjustment *adjustment; - for (i = 0; i < clist->columns; i++) - { - GTK_CLIST_CLASS_FW (clist)->set_cell_contents - (clist, clist_row, i, GTK_CELL_EMPTY, NULL, 0, NULL, NULL); - if (clist_row->cell[i].style) - { - if (GTK_WIDGET_REALIZED (clist)) - gtk_style_detach (clist_row->cell[i].style); - gtk_style_unref (clist_row->cell[i].style); - } - } + clist->vscrollbar = gtk_vscrollbar_new (NULL); - if (clist_row->style) - { - if (GTK_WIDGET_REALIZED (clist)) - gtk_style_detach (clist_row->style); - gtk_style_unref (clist_row->style); - } + adjustment = gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar)); - if (clist_row->destroy) - clist_row->destroy (clist_row->data); + gtk_signal_connect (GTK_OBJECT (adjustment), "changed", + (GtkSignalFunc) vadjustment_changed, + (gpointer) clist); - g_mem_chunk_free (clist->cell_mem_chunk, clist_row->cell); - g_mem_chunk_free (clist->row_mem_chunk, clist_row); + gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed", + (GtkSignalFunc) vadjustment_value_changed, + (gpointer) clist); + + gtk_widget_set_parent (clist->vscrollbar, GTK_WIDGET (clist)); + gtk_widget_show (clist->vscrollbar); + + clist->hscrollbar = gtk_hscrollbar_new (NULL); + + adjustment = gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar)); + + gtk_signal_connect (GTK_OBJECT (adjustment), "changed", + (GtkSignalFunc) hadjustment_changed, + (gpointer) clist); + + gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed", + (GtkSignalFunc) hadjustment_value_changed, + (gpointer) clist); + + gtk_widget_set_parent (clist->hscrollbar, GTK_WIDGET (clist)); + gtk_widget_show (clist->hscrollbar); } static void -set_cell_contents (GtkCList *clist, - GtkCListRow *clist_row, - gint column, - GtkCellType type, - const gchar *text, - guint8 spacing, - GdkPixmap *pixmap, - GdkBitmap *mask) +adjust_scrollbars (GtkCList * clist) { - g_return_if_fail (clist_row != NULL); + GtkRange *vscrollbar; + GtkRange *hscrollbar; - switch (clist_row->cell[column].type) + vscrollbar = GTK_RANGE (clist->vscrollbar); + vscrollbar->adjustment->page_size = clist->clist_window_height; + vscrollbar->adjustment->page_increment = clist->clist_window_height / 2; + vscrollbar->adjustment->step_increment = 10; + vscrollbar->adjustment->lower = 0; + vscrollbar->adjustment->upper = LIST_HEIGHT (clist); + + if (clist->clist_window_height - clist->voffset > LIST_HEIGHT (clist)) { - case GTK_CELL_EMPTY: - break; - case GTK_CELL_TEXT: - g_free (GTK_CELL_TEXT (clist_row->cell[column])->text); - break; - case GTK_CELL_PIXMAP: - gdk_pixmap_unref (GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap); - if (GTK_CELL_PIXMAP (clist_row->cell[column])->mask) - gdk_bitmap_unref (GTK_CELL_PIXMAP (clist_row->cell[column])->mask); - break; - case GTK_CELL_PIXTEXT: - g_free (GTK_CELL_PIXTEXT (clist_row->cell[column])->text); - gdk_pixmap_unref (GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap); - if (GTK_CELL_PIXTEXT (clist_row->cell[column])->mask) - gdk_bitmap_unref (GTK_CELL_PIXTEXT (clist_row->cell[column])->mask); - break; - case GTK_CELL_WIDGET: - /* unimplimented */ - break; - default: - break; + vscrollbar->adjustment->value = MAX (0, LIST_HEIGHT (clist) - + clist->clist_window_height); + gtk_signal_emit_by_name (GTK_OBJECT (vscrollbar->adjustment), + "value_changed"); } - clist_row->cell[column].type = GTK_CELL_EMPTY; + hscrollbar = GTK_RANGE (clist->hscrollbar); + hscrollbar->adjustment->page_size = clist->clist_window_width; + hscrollbar->adjustment->page_increment = clist->clist_window_width / 2; + hscrollbar->adjustment->step_increment = 10; + hscrollbar->adjustment->lower = 0; + hscrollbar->adjustment->upper = LIST_WIDTH (clist); - switch (type) + if (clist->clist_window_width - clist->hoffset > LIST_WIDTH (clist)) { - case GTK_CELL_TEXT: - if (text) - { - clist_row->cell[column].type = GTK_CELL_TEXT; - GTK_CELL_TEXT (clist_row->cell[column])->text = g_strdup (text); - } - break; - case GTK_CELL_PIXMAP: - if (pixmap) + hscrollbar->adjustment->value = MAX (0, LIST_WIDTH (clist) - + clist->clist_window_width); + gtk_signal_emit_by_name (GTK_OBJECT (hscrollbar->adjustment), + "value_changed"); + } + + if (LIST_HEIGHT (clist) <= clist->clist_window_height && + clist->vscrollbar_policy == GTK_POLICY_AUTOMATIC) + { + if (GTK_WIDGET_VISIBLE (clist->vscrollbar)) { - clist_row->cell[column].type = GTK_CELL_PIXMAP; - GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap = pixmap; - /* We set the mask even if it is NULL */ - GTK_CELL_PIXMAP (clist_row->cell[column])->mask = mask; + gtk_widget_hide (clist->vscrollbar); + gtk_widget_size_allocate (GTK_WIDGET (clist), + >K_WIDGET (clist)->allocation); } - break; - case GTK_CELL_PIXTEXT: - if (text && pixmap) + } + else + { + if (!GTK_WIDGET_VISIBLE (clist->vscrollbar)) { - clist_row->cell[column].type = GTK_CELL_PIXTEXT; - GTK_CELL_PIXTEXT (clist_row->cell[column])->text = g_strdup (text); - GTK_CELL_PIXTEXT (clist_row->cell[column])->spacing = spacing; - GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap = pixmap; - GTK_CELL_PIXTEXT (clist_row->cell[column])->mask = mask; + gtk_widget_show (clist->vscrollbar); + gtk_widget_size_allocate (GTK_WIDGET (clist), + >K_WIDGET (clist)->allocation); } - break; - default: - break; } -} - -/* Fill in data after widget has correct style */ - -static void -add_style_data (GtkCList * clist) -{ - GtkWidget *widget; - - widget = GTK_WIDGET(clist); - /* text properties */ - if (!GTK_CLIST_ROW_HEIGHT_SET (clist)) + if (LIST_WIDTH (clist) <= clist->clist_window_width && + clist->hscrollbar_policy == GTK_POLICY_AUTOMATIC) { - clist->row_height = widget->style->font->ascent + widget->style->font->descent + 1; - clist->row_center_offset = widget->style->font->ascent + 1.5; + if (GTK_WIDGET_VISIBLE (clist->hscrollbar)) + { + gtk_widget_hide (clist->hscrollbar); + gtk_widget_size_allocate (GTK_WIDGET (clist), + >K_WIDGET (clist)->allocation); + } } else { - gint text_height; - text_height = clist->row_height - (GTK_WIDGET (clist)->style->font->ascent + - GTK_WIDGET (clist) ->style->font->descent + 1); - clist->row_center_offset = (text_height / 2) + GTK_WIDGET (clist)->style->font->ascent + 1.5; + if (!GTK_WIDGET_VISIBLE (clist->hscrollbar)) + { + gtk_widget_show (clist->hscrollbar); + gtk_widget_size_allocate (GTK_WIDGET (clist), + >K_WIDGET (clist)->allocation); + } } - /* Column widths */ + gtk_signal_emit_by_name (GTK_OBJECT (vscrollbar->adjustment), "changed"); + gtk_signal_emit_by_name (GTK_OBJECT (hscrollbar->adjustment), "changed"); } - -/* focus functions */ - static void -gtk_clist_draw_focus (GtkWidget *widget) +vadjustment_changed (GtkAdjustment *adjustment, + gpointer data) { GtkCList *clist; - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_CLIST (widget)); - - if (!GTK_WIDGET_DRAWABLE (widget)) - return; + g_return_if_fail (adjustment != NULL); + g_return_if_fail (data != NULL); - clist = GTK_CLIST (widget); - if (clist->focus_row >= 0) - gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, - 0, ROW_TOP_YPIXEL(clist, clist->focus_row), - clist->clist_window_width - 1, - clist->row_height - 1); + clist = GTK_CLIST (data); } static void -gtk_clist_set_focus_child (GtkContainer *container, - GtkWidget *child) -{ - g_return_if_fail (container != NULL); - g_return_if_fail (GTK_IS_CLIST (container)); - - if (child) - { - g_return_if_fail (GTK_IS_WIDGET (child)); - GTK_CLIST_SET_FLAG (GTK_CLIST (container), CLIST_CHILD_HAS_FOCUS); - } - - parent_class->set_focus_child (container, child); -} - -static gint -gtk_clist_focus_in (GtkWidget *widget, - GdkEventFocus *event) +hadjustment_changed (GtkAdjustment *adjustment, + gpointer data) { GtkCList *clist; - g_return_val_if_fail (widget != NULL, FALSE); - g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - - GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS); - GTK_CLIST_UNSET_FLAG (widget, CLIST_CHILD_HAS_FOCUS); - - clist = GTK_CLIST (widget); - - if (clist->selection_mode == GTK_SELECTION_BROWSE && - clist->selection == NULL && clist->focus_row > -1) - { - GList *list; - - list = g_list_nth (clist->row_list, clist->focus_row); - if (list && GTK_CLIST_ROW (list)->selectable) - select_row (clist, clist->focus_row, -1, (GdkEvent *) event); - else - gtk_widget_draw_focus (widget); - } - else - gtk_widget_draw_focus (widget); + g_return_if_fail (adjustment != NULL); + g_return_if_fail (data != NULL); - return FALSE; + clist = GTK_CLIST (data); } -static gint -gtk_clist_focus_out (GtkWidget *widget, - GdkEventFocus *event) +static void +vadjustment_value_changed (GtkAdjustment *adjustment, + gpointer data) { GtkCList *clist; + GdkRectangle area; + gint diff, value; - g_return_val_if_fail (widget != NULL, FALSE); - g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - - GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS); - gtk_widget_draw_focus (widget); - - clist = GTK_CLIST (widget); - - if (clist->anchor != -1 && clist->selection_mode == GTK_SELECTION_EXTENDED) - GTK_CLIST_CLASS_FW (widget)->resync_selection (clist, (GdkEvent *) event); + g_return_if_fail (adjustment != NULL); + g_return_if_fail (data != NULL); + g_return_if_fail (GTK_IS_CLIST (data)); - return FALSE; -} + clist = GTK_CLIST (data); -static void -toggle_add_mode (GtkCList *clist) -{ - g_return_if_fail (clist != 0); - g_return_if_fail (GTK_IS_CLIST (clist)); - - if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) || - clist->selection_mode != GTK_SELECTION_EXTENDED) + if (!GTK_WIDGET_DRAWABLE (clist)) return; - gtk_clist_draw_focus (GTK_WIDGET (clist)); - if (!GTK_CLIST_ADD_MODE (clist)) - { - GTK_CLIST_SET_FLAG (clist, CLIST_ADD_MODE); - gdk_gc_set_line_attributes (clist->xor_gc, 1, - GDK_LINE_ON_OFF_DASH, 0, 0); - gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2); - } - else - { - GTK_CLIST_UNSET_FLAG (clist, CLIST_ADD_MODE); - gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_SOLID, 0, 0); - clist->anchor_state = GTK_STATE_SELECTED; - } - gtk_clist_draw_focus (GTK_WIDGET (clist)); -} + value = adjustment->value; -static void -toggle_focus_row (GtkCList *clist) -{ - g_return_if_fail (clist != 0); - g_return_if_fail (GTK_IS_CLIST (clist)); + if (adjustment == gtk_range_get_adjustment (GTK_RANGE (clist->vscrollbar))) + { + if (value > -clist->voffset) + { + /* scroll down */ + diff = value + clist->voffset; - if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) || - clist->focus_row < 0 || clist->focus_row >= clist->rows) - return; + /* we have to re-draw the whole screen here... */ + if (diff >= clist->clist_window_height) + { + clist->voffset = -value; + draw_rows (clist, NULL); + return; + } - switch (clist->selection_mode) - { - case GTK_SELECTION_SINGLE: - case GTK_SELECTION_MULTIPLE: - toggle_row (clist, clist->focus_row, 0, NULL); - break; - case GTK_SELECTION_EXTENDED: - g_list_free (clist->undo_selection); - g_list_free (clist->undo_unselection); - clist->undo_selection = NULL; - clist->undo_unselection = NULL; + if ((diff != 0) && (diff != clist->clist_window_height)) + gdk_window_copy_area (clist->clist_window, + clist->fg_gc, + 0, 0, + clist->clist_window, + 0, + diff, + clist->clist_window_width, + clist->clist_window_height - diff); - clist->anchor = clist->focus_row; - clist->drag_pos = clist->focus_row; - clist->undo_anchor = clist->focus_row; - - if (GTK_CLIST_ADD_MODE (clist)) - fake_toggle_row (clist, clist->focus_row); + area.x = 0; + area.y = clist->clist_window_height - diff; + area.width = clist->clist_window_width; + area.height = diff; + } else - GTK_CLIST_CLASS_FW (clist)->fake_unselect_all (clist,clist->focus_row); - - GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL); - break; - default: - break; - } -} + { + /* scroll up */ + diff = -clist->voffset - value; -static void -move_focus_row (GtkCList *clist, - GtkScrollType scroll_type, - gfloat position) -{ - GtkWidget *widget; + /* we have to re-draw the whole screen here... */ + if (diff >= clist->clist_window_height) + { + clist->voffset = -value; + draw_rows (clist, NULL); + return; + } - g_return_if_fail (clist != 0); - g_return_if_fail (GTK_IS_CLIST (clist)); + if ((diff != 0) && (diff != clist->clist_window_height)) + gdk_window_copy_area (clist->clist_window, + clist->fg_gc, + 0, diff, + clist->clist_window, + 0, + 0, + clist->clist_window_width, + clist->clist_window_height - diff); - widget = GTK_WIDGET (clist); + area.x = 0; + area.y = 0; + area.width = clist->clist_window_width; + area.height = diff; - switch (scroll_type) - { - case GTK_SCROLL_STEP_BACKWARD: - if (clist->focus_row <= 0) - return; - gtk_clist_draw_focus (widget); - clist->focus_row--; - gtk_clist_draw_focus (widget); - break; - case GTK_SCROLL_STEP_FORWARD: - if (clist->focus_row >= clist->rows - 1) - return; - gtk_clist_draw_focus (widget); - clist->focus_row++; - gtk_clist_draw_focus (widget); - break; - case GTK_SCROLL_PAGE_BACKWARD: - if (clist->focus_row <= 0) - return; - gtk_clist_draw_focus (widget); - clist->focus_row = MAX (0, clist->focus_row - - (2 * clist->clist_window_height - - clist->row_height - CELL_SPACING) / - (2 * (clist->row_height + CELL_SPACING))); - gtk_clist_draw_focus (widget); - break; - case GTK_SCROLL_PAGE_FORWARD: - if (clist->focus_row >= clist->rows - 1) - return; - gtk_clist_draw_focus (widget); - clist->focus_row = MIN (clist->rows - 1, clist->focus_row + - (2 * clist->clist_window_height - - clist->row_height - CELL_SPACING) / - (2 * (clist->row_height + CELL_SPACING))); - gtk_clist_draw_focus (widget); - break; - case GTK_SCROLL_JUMP: - if (position >= 0 && position <= 1) - { - gtk_clist_draw_focus (widget); - clist->focus_row = position * (clist->rows - 1); - gtk_clist_draw_focus (widget); } - break; - default: - break; + + clist->voffset = -value; + if ((diff != 0) && (diff != clist->clist_window_height)) + check_exposures (clist); } + + draw_rows (clist, &area); } static void -scroll_horizontal (GtkCList *clist, - GtkScrollType scroll_type, - gfloat position) +hadjustment_value_changed (GtkAdjustment *adjustment, + gpointer data) { - gint column = 0; + GtkCList *clist; + GdkRectangle area; + gint i; + gint y = 0; + gint diff = 0; + gint value; - g_return_if_fail (clist != 0); - g_return_if_fail (GTK_IS_CLIST (clist)); + g_return_if_fail (adjustment != NULL); + g_return_if_fail (data != NULL); + g_return_if_fail (GTK_IS_CLIST (data)); - if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) + clist = GTK_CLIST (data); + + if (!GTK_WIDGET_DRAWABLE (clist) || + adjustment != gtk_range_get_adjustment (GTK_RANGE (clist->hscrollbar))) return; - switch (scroll_type) + value = adjustment->value; + + /* move the column buttons and resize windows */ + for (i = 0; i < clist->columns; i++) { - case GTK_SCROLL_STEP_BACKWARD: - column = COLUMN_FROM_XPIXEL (clist, 0); - if (COLUMN_LEFT_XPIXEL (clist, column) - CELL_SPACING - COLUMN_INSET >= 0 - && column > 0) - column--; - break; - case GTK_SCROLL_STEP_FORWARD: - column = COLUMN_FROM_XPIXEL (clist, clist->clist_window_width); - if (column < 0) - return; - if (COLUMN_LEFT_XPIXEL (clist, column) + clist->column[column].area.width - + CELL_SPACING + COLUMN_INSET - 1 <= clist->clist_window_width && - column < clist->columns - 1) - column++; - break; - case GTK_SCROLL_PAGE_BACKWARD: - case GTK_SCROLL_PAGE_FORWARD: - return; - case GTK_SCROLL_JUMP: - if (position >= 0 && position <= 1) - column = position * (clist->columns - 1); - else - return; - break; - default: - break; + if (clist->column[i].button) + { + clist->column[i].button->allocation.x -= value + clist->hoffset; + + if (clist->column[i].button->window) + { + gdk_window_move (clist->column[i].button->window, + clist->column[i].button->allocation.x, + clist->column[i].button->allocation.y); + + if (clist->column[i].window) + gdk_window_move (clist->column[i].window, + clist->column[i].button->allocation.x + + clist->column[i].button->allocation.width - + (DRAG_WIDTH / 2), 0); + } + } } - if (COLUMN_LEFT_XPIXEL (clist, column) < CELL_SPACING + COLUMN_INSET) - gtk_clist_moveto (clist, -1, column, 0, 0); - else if (COLUMN_LEFT_XPIXEL (clist, column) + CELL_SPACING + COLUMN_INSET - 1 - + clist->column[column].area.width > clist->clist_window_width) + if (value > -clist->hoffset) { - if (column == clist->columns - 1) - gtk_clist_moveto (clist, -1, column, 0, 0); - else - gtk_clist_moveto (clist, -1, column, 0, 1); - } -} - -static void -scroll_vertical (GtkCList *clist, - GtkScrollType scroll_type, - gfloat position) -{ - gint old_focus_row; - - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); + /* scroll right */ + diff = value + clist->hoffset; + + clist->hoffset = -value; + + /* we have to re-draw the whole screen here... */ + if (diff >= clist->clist_window_width) + { + draw_rows (clist, NULL); + return; + } - if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) - return; + if (GTK_WIDGET_HAS_FOCUS (clist) && !GTK_CLIST_CHILD_HAS_FOCUS (clist) && + GTK_CLIST_ADD_MODE (clist)) + { + y = ROW_TOP_YPIXEL (clist, clist->focus_row); + + gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, 0, y, + clist->clist_window_width - 1, + clist->row_height - 1); + } + gdk_window_copy_area (clist->clist_window, + clist->fg_gc, + 0, 0, + clist->clist_window, + diff, + 0, + clist->clist_window_width - diff, + clist->clist_window_height); - switch (clist->selection_mode) + area.x = clist->clist_window_width - diff; + } + else { - case GTK_SELECTION_EXTENDED: - if (clist->anchor >= 0) + /* scroll left */ + if (!(diff = -clist->hoffset - value)) return; - case GTK_SELECTION_BROWSE: + clist->hoffset = -value; + + /* we have to re-draw the whole screen here... */ + if (diff >= clist->clist_window_width) + { + draw_rows (clist, NULL); + return; + } + + if (GTK_WIDGET_HAS_FOCUS (clist) && !GTK_CLIST_CHILD_HAS_FOCUS (clist) && + GTK_CLIST_ADD_MODE (clist)) + { + y = ROW_TOP_YPIXEL (clist, clist->focus_row); + + gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, 0, y, + clist->clist_window_width - 1, + clist->row_height - 1); + } - old_focus_row = clist->focus_row; - move_focus_row (clist, scroll_type, position); + gdk_window_copy_area (clist->clist_window, + clist->fg_gc, + diff, 0, + clist->clist_window, + 0, + 0, + clist->clist_window_width - diff, + clist->clist_window_height); + + area.x = 0; + } - if (old_focus_row != clist->focus_row) + area.y = 0; + area.width = diff; + area.height = clist->clist_window_height; + + check_exposures (clist); + + if (GTK_WIDGET_HAS_FOCUS (clist) && !GTK_CLIST_CHILD_HAS_FOCUS (clist)) + { + if (GTK_CLIST_ADD_MODE (clist)) { - if (clist->selection_mode == GTK_SELECTION_BROWSE) - unselect_row (clist,old_focus_row, -1, NULL); - else if (!GTK_CLIST_ADD_MODE (clist)) - { - gtk_clist_unselect_all (clist); - clist->undo_anchor = old_focus_row; - } + gint focus_row; + + focus_row = clist->focus_row; + clist->focus_row = -1; + draw_rows (clist, &area); + clist->focus_row = focus_row; + + gdk_draw_rectangle (clist->clist_window, clist->xor_gc, + FALSE, 0, y, clist->clist_window_width - 1, + clist->row_height - 1); + return; } - - switch (gtk_clist_row_is_visible (clist, clist->focus_row)) + else { - case GTK_VISIBILITY_NONE: - if (old_focus_row != clist->focus_row && - !(clist->selection_mode == GTK_SELECTION_EXTENDED && - GTK_CLIST_ADD_MODE (clist))) - select_row (clist, clist->focus_row, -1, NULL); - switch (scroll_type) + gint x0; + gint x1; + + if (area.x == 0) { - case GTK_SCROLL_STEP_BACKWARD: - case GTK_SCROLL_PAGE_BACKWARD: - gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0); - break; - case GTK_SCROLL_STEP_FORWARD: - case GTK_SCROLL_PAGE_FORWARD: - gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0); - break; - case GTK_SCROLL_JUMP: - gtk_clist_moveto (clist, clist->focus_row, -1, 0.5, 0); - break; - default: - break; + x0 = clist->clist_window_width - 1; + x1 = diff; } - break; - - case GTK_VISIBILITY_PARTIAL: - switch (scroll_type) + else { - case GTK_SCROLL_STEP_BACKWARD: - case GTK_SCROLL_PAGE_BACKWARD: - gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0); - break; - case GTK_SCROLL_STEP_FORWARD: - case GTK_SCROLL_PAGE_FORWARD: - gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0); - break; - case GTK_SCROLL_JUMP: - gtk_clist_moveto (clist, clist->focus_row, -1, 0.5, 0); - break; - default: - break; - } - - default: - if (old_focus_row != clist->focus_row && - !(clist->selection_mode == GTK_SELECTION_EXTENDED && - GTK_CLIST_ADD_MODE (clist))) - select_row (clist, clist->focus_row, -1, NULL); - break; - } - break; - - default: - move_focus_row (clist, scroll_type, position); - - if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height > - clist->clist_window_height) - gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0); - else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0) - gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0); - break; + x0 = 0; + x1 = area.x - 1; + } + + y = ROW_TOP_YPIXEL (clist, clist->focus_row); + gdk_draw_line (clist->clist_window, clist->xor_gc, + x0, y + 1, x0, y + clist->row_height - 2); + gdk_draw_line (clist->clist_window, clist->xor_gc, + x1, y + 1, x1, y + clist->row_height - 2); + + } } + draw_rows (clist, &area); } static void -set_anchor (GtkCList *clist, - gboolean add_mode, - gint anchor, - gint undo_anchor) +check_exposures (GtkCList *clist) { - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); - - if (clist->selection_mode != GTK_SELECTION_EXTENDED || clist->anchor >= 0) - return; + GdkEvent *event; - g_list_free (clist->undo_selection); - g_list_free (clist->undo_unselection); - clist->undo_selection = NULL; - clist->undo_unselection = NULL; + if (!GTK_WIDGET_REALIZED (clist)) + return; - if (add_mode) - fake_toggle_row (clist, anchor); - else + /* Make sure graphics expose events are processed before scrolling + * again */ + while ((event = gdk_event_get_graphics_expose (clist->clist_window)) != NULL) { - GTK_CLIST_CLASS_FW (clist)->fake_unselect_all (clist, anchor); - clist->anchor_state = GTK_STATE_SELECTED; + gtk_widget_event (GTK_WIDGET (clist), event); + if (event->expose.count == 0) + { + gdk_event_free (event); + break; + } + gdk_event_free (event); } - - clist->anchor = anchor; - clist->drag_pos = anchor; - clist->undo_anchor = undo_anchor; } -static void -resync_selection (GtkCList *clist, - GdkEvent *event) +/* + * Memory Allocation/Distruction Routines for GtkCList stuctures + * + * functions: + * columns_new + * column_title_new + * columns_delete + * row_new + * row_delete + */ +static GtkCListColumn * +columns_new (GtkCList *clist) { + GtkCListColumn *column; gint i; - gint e; - gint row; - gboolean thaw = FALSE; - GList *list; - GtkCListRow *clist_row; - if (clist->anchor < 0) - return; + column = g_new (GtkCListColumn, clist->columns); - if (!GTK_CLIST_FROZEN (clist)) + for (i = 0; i < clist->columns; i++) { - GTK_CLIST_SET_FLAG (clist, CLIST_FROZEN); - thaw = TRUE; + column[i].area.x = 0; + column[i].area.y = 0; + column[i].area.width = 0; + column[i].area.height = 0; + column[i].title = NULL; + column[i].button = NULL; + column[i].window = NULL; + column[i].width = 0; + column[i].min_width = -1; + column[i].max_width = -1; + column[i].visible = TRUE; + column[i].width_set = FALSE; + column[i].resizeable = TRUE; + column[i].auto_resize = FALSE; + column[i].justification = GTK_JUSTIFY_LEFT; } - i = MIN (clist->anchor, clist->drag_pos); - e = MAX (clist->anchor, clist->drag_pos); - - if (clist->undo_selection) - { - list = clist->selection; - clist->selection = clist->undo_selection; - clist->selection_end = g_list_last (clist->selection); - clist->undo_selection = list; - list = clist->selection; - while (list) - { - row = GPOINTER_TO_INT (list->data); - list = list->next; - if (row < i || row > e) - { - clist_row = g_list_nth (clist->row_list, row)->data; - if (clist_row->selectable) - { - clist_row->state = GTK_STATE_SELECTED; - unselect_row (clist, row, -1, event); - clist->undo_selection = g_list_prepend - (clist->undo_selection, GINT_TO_POINTER (row)); - } - } - } - } - - for (list = g_list_nth (clist->row_list, i); i <= e; i++, list = list->next) - if (GTK_CLIST_ROW (list)->selectable) - { - if (g_list_find (clist->selection, GINT_TO_POINTER(i))) - { - if (GTK_CLIST_ROW (list)->state == GTK_STATE_NORMAL) - { - GTK_CLIST_ROW (list)->state = GTK_STATE_SELECTED; - unselect_row (clist, i, -1, event); - clist->undo_selection = g_list_prepend (clist->undo_selection, - GINT_TO_POINTER (i)); - } - } - else if (GTK_CLIST_ROW (list)->state == GTK_STATE_SELECTED) - { - GTK_CLIST_ROW (list)->state = GTK_STATE_NORMAL; - clist->undo_unselection = g_list_prepend (clist->undo_unselection, - GINT_TO_POINTER (i)); - } - } - - for (list = clist->undo_unselection; list; list = list->next) - gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], - GPOINTER_TO_INT (list->data), -1, event); + return column; +} - clist->anchor = -1; - clist->drag_pos = -1; +static void +column_title_new (GtkCList *clist, + gint column, + const gchar *title) +{ + if (clist->column[column].title) + g_free (clist->column[column].title); - if (thaw) - GTK_CLIST_UNSET_FLAG (clist, CLIST_FROZEN); + clist->column[column].title = g_strdup (title); } static void -update_extended_selection (GtkCList *clist, - gint row) +columns_delete (GtkCList *clist) { gint i; - GList *list; - GdkRectangle area; - gint s1 = -1; - gint s2 = -1; - gint e1 = -1; - gint e2 = -1; - gint y1 = clist->clist_window_height; - gint y2 = clist->clist_window_height; - gint h1 = 0; - gint h2 = 0; - gint top; - if (clist->selection_mode != GTK_SELECTION_EXTENDED || clist->anchor == -1) - return; + for (i = 0; i < clist->columns; i++) + if (clist->column[i].title) + g_free (clist->column[i].title); + + g_free (clist->column); +} - if (row < 0) - row = 0; - if (row >= clist->rows) - row = clist->rows - 1; +static GtkCListRow * +row_new (GtkCList *clist) +{ + int i; + GtkCListRow *clist_row; - /* extending downwards */ - if (row > clist->drag_pos && clist->anchor <= clist->drag_pos) - { - s2 = clist->drag_pos + 1; - e2 = row; - } - /* extending upwards */ - else if (row < clist->drag_pos && clist->anchor >= clist->drag_pos) + clist_row = g_chunk_new (GtkCListRow, clist->row_mem_chunk); + clist_row->cell = g_chunk_new (GtkCell, clist->cell_mem_chunk); + + for (i = 0; i < clist->columns; i++) { - s2 = row; - e2 = clist->drag_pos - 1; + clist_row->cell[i].type = GTK_CELL_EMPTY; + clist_row->cell[i].vertical = 0; + clist_row->cell[i].horizontal = 0; + clist_row->cell[i].style = NULL; } - else if (row < clist->drag_pos && clist->anchor < clist->drag_pos) + + clist_row->fg_set = FALSE; + clist_row->bg_set = FALSE; + clist_row->style = NULL; + clist_row->selectable = TRUE; + clist_row->state = GTK_STATE_NORMAL; + clist_row->data = NULL; + clist_row->destroy = NULL; + + return clist_row; +} + +static void +row_delete (GtkCList *clist, + GtkCListRow *clist_row) +{ + gint i; + + for (i = 0; i < clist->columns; i++) { - e1 = clist->drag_pos; - /* row and drag_pos on different sides of anchor : - take back the selection between anchor and drag_pos, - select between anchor and row */ - if (row < clist->anchor) + GTK_CLIST_CLASS_FW (clist)->set_cell_contents + (clist, clist_row, i, GTK_CELL_EMPTY, NULL, 0, NULL, NULL); + if (clist_row->cell[i].style) { - s1 = clist->anchor + 1; - s2 = row; - e2 = clist->anchor - 1; + if (GTK_WIDGET_REALIZED (clist)) + gtk_style_detach (clist_row->cell[i].style); + gtk_style_unref (clist_row->cell[i].style); } - /* take back the selection between anchor and drag_pos */ - else - s1 = row + 1; } - else if (row > clist->drag_pos && clist->anchor > clist->drag_pos) + + if (clist_row->style) { - s1 = clist->drag_pos; - /* row and drag_pos on different sides of anchor : - take back the selection between anchor and drag_pos, - select between anchor and row */ - if (row > clist->anchor) - { - e1 = clist->anchor - 1; - s2 = clist->anchor + 1; - e2 = row; - } - /* take back the selection between anchor and drag_pos */ - else - e1 = row - 1; + if (GTK_WIDGET_REALIZED (clist)) + gtk_style_detach (clist_row->style); + gtk_style_unref (clist_row->style); } - clist->drag_pos = row; + if (clist_row->destroy) + clist_row->destroy (clist_row->data); + + g_mem_chunk_free (clist->cell_mem_chunk, clist_row->cell); + g_mem_chunk_free (clist->row_mem_chunk, clist_row); +} - area.x = 0; - area.width = clist->clist_window_width; +/* FOCUS FUNCTIONS + * gtk_clist_focus + * gtk_clist_draw_focus + * gtk_clist_focus_in + * gtk_clist_focus_out + * gtk_clist_set_focus_child + * title_focus + */ +static gint +gtk_clist_focus (GtkContainer *container, + GtkDirectionType direction) +{ + GtkCList *clist; + GtkWidget *focus_child; + gint old_row; - /* restore the elements between s1 and e1 */ - if (s1 >= 0) - { - for (i = s1, list = g_list_nth (clist->row_list, i); i <= e1; - i++, list = list->next) - if (GTK_CLIST_ROW (list)->selectable) - { - if (GTK_CLIST_CLASS_FW (clist)->selection_find (clist, i, list)) - GTK_CLIST_ROW (list)->state = GTK_STATE_SELECTED; - else - GTK_CLIST_ROW (list)->state = GTK_STATE_NORMAL; - } + g_return_val_if_fail (container != NULL, FALSE); + g_return_val_if_fail (GTK_IS_CLIST (container), FALSE); - top = ROW_TOP_YPIXEL (clist, clist->focus_row); + if (!GTK_WIDGET_SENSITIVE (container)) + return FALSE; + + clist = GTK_CLIST (container); + focus_child = container->focus_child; + old_row = clist->focus_row; - if (top + clist->row_height <= 0) + switch (direction) + { + case GTK_DIR_LEFT: + case GTK_DIR_RIGHT: + if (GTK_CLIST_CHILD_HAS_FOCUS (clist) && + (!focus_child || (focus_child && focus_child != clist->vscrollbar && + focus_child != clist->hscrollbar))) { - area.y = 0; - area.height = ROW_TOP_YPIXEL (clist, e1) + clist->row_height; - draw_rows (clist, &area); - gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0); - } - else if (top >= clist->clist_window_height) + if (title_focus (clist, direction)) + return TRUE; + gtk_container_set_focus_child (container, NULL); + return FALSE; + } + gtk_widget_grab_focus (GTK_WIDGET (container)); + return TRUE; + case GTK_DIR_DOWN: + case GTK_DIR_TAB_FORWARD: + if (GTK_CLIST_CHILD_HAS_FOCUS (clist) && + (!focus_child || (focus_child != clist->vscrollbar && + focus_child != clist->hscrollbar))) { - area.y = ROW_TOP_YPIXEL (clist, s1) - 1; - area.height = clist->clist_window_height - area.y; - draw_rows (clist, &area); - gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0); - } - else if (top < 0) - gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0); - else if (top + clist->row_height > clist->clist_window_height) - gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0); + gboolean tf = FALSE; - y1 = ROW_TOP_YPIXEL (clist, s1) - 1; - h1 = (e1 - s1 + 1) * (clist->row_height + CELL_SPACING); - } + if (((focus_child && direction == GTK_DIR_DOWN) || + !(tf = title_focus (clist, GTK_DIR_TAB_FORWARD))) + && clist->rows) + { + if (clist->focus_row < 0) + { + clist->focus_row = 0; - /* extend the selection between s2 and e2 */ - if (s2 >= 0) - { - for (i = s2, list = g_list_nth (clist->row_list, i); i <= e2; - i++, list = list->next) - if (GTK_CLIST_ROW (list)->selectable && - GTK_CLIST_ROW (list)->state != clist->anchor_state) - GTK_CLIST_ROW (list)->state = clist->anchor_state; + if ((clist->selection_mode == GTK_SELECTION_BROWSE || + clist->selection_mode == GTK_SELECTION_EXTENDED) && + !clist->selection) + gtk_signal_emit (GTK_OBJECT (clist), + clist_signals[SELECT_ROW], + clist->focus_row, -1, NULL); + } + gtk_widget_grab_focus (GTK_WIDGET (container)); + return TRUE; + } - top = ROW_TOP_YPIXEL (clist, clist->focus_row); + if (tf) + return TRUE; + } + + GTK_CLIST_SET_FLAG (clist, CLIST_CHILD_HAS_FOCUS); - if (top + clist->row_height <= 0) + if ((!GTK_CLIST_CHILD_HAS_FOCUS (clist) || !focus_child || + (focus_child != clist->vscrollbar && + focus_child != clist->hscrollbar)) && + GTK_WIDGET_VISIBLE (clist->vscrollbar) && + GTK_WIDGET_CAN_FOCUS (clist->vscrollbar)) { - area.y = 0; - area.height = ROW_TOP_YPIXEL (clist, e2) + clist->row_height; - draw_rows (clist, &area); - gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0); + gtk_widget_grab_focus (clist->vscrollbar); + return TRUE; } - else if (top >= clist->clist_window_height) + + if ((!GTK_CLIST_CHILD_HAS_FOCUS (clist) || !focus_child || + focus_child != clist->hscrollbar) && + GTK_WIDGET_VISIBLE (clist->hscrollbar) && + GTK_WIDGET_CAN_FOCUS (clist->hscrollbar)) { - area.y = ROW_TOP_YPIXEL (clist, s2) - 1; - area.height = clist->clist_window_height - area.y; - draw_rows (clist, &area); - gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0); + gtk_widget_grab_focus (clist->hscrollbar); + return TRUE; + } + break; + case GTK_DIR_UP: + case GTK_DIR_TAB_BACKWARD: + if (!focus_child && GTK_CLIST_CHILD_HAS_FOCUS (clist) && + GTK_WIDGET_VISIBLE (clist->hscrollbar) && + GTK_WIDGET_CAN_FOCUS (clist->hscrollbar)) + { + gtk_widget_grab_focus (clist->hscrollbar); + return TRUE; + } + + if ((!focus_child || focus_child == clist->hscrollbar) && + GTK_CLIST_CHILD_HAS_FOCUS (clist) && + GTK_WIDGET_VISIBLE (clist->vscrollbar) && + GTK_WIDGET_CAN_FOCUS (clist->vscrollbar)) + { + gtk_widget_grab_focus (clist->vscrollbar); + return TRUE; } - else if (top < 0) - gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0); - else if (top + clist->row_height > clist->clist_window_height) - gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0); - - y2 = ROW_TOP_YPIXEL (clist, s2) - 1; - h2 = (e2 - s2 + 1) * (clist->row_height + CELL_SPACING); - } - - area.y = MAX (0, MIN (y1, y2)); - if (area.y > clist->clist_window_height) - area.y = 0; - area.height = MIN (clist->clist_window_height, h1 + h2); - if (s1 >= 0 && s2 >= 0) - area.height += (clist->row_height + CELL_SPACING); - draw_rows (clist, &area); -} -static void -start_selection (GtkCList *clist) -{ - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); + if ((!focus_child || focus_child == clist->hscrollbar || + focus_child == clist->vscrollbar) && + GTK_CLIST_CHILD_HAS_FOCUS (clist) && clist->rows) + { + if (clist->focus_row < 0) + { + clist->focus_row = 0; + if ((clist->selection_mode == GTK_SELECTION_BROWSE || + clist->selection_mode == GTK_SELECTION_EXTENDED) && + !clist->selection) + gtk_signal_emit (GTK_OBJECT (clist), + clist_signals[SELECT_ROW], + clist->focus_row, -1, NULL); + } + gtk_widget_grab_focus (GTK_WIDGET (container)); + return TRUE; + } - if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) - return; + GTK_CLIST_SET_FLAG (clist, CLIST_CHILD_HAS_FOCUS); - set_anchor (clist, GTK_CLIST_ADD_MODE (clist), clist->focus_row, - clist->focus_row); -} + if (title_focus (clist, direction)) + return TRUE; -static void -end_selection (GtkCList *clist) -{ - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); + break; + default: + break; + } - if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_FOCUS (clist)) || - clist->anchor == -1) - return; - - GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL); + gtk_container_set_focus_child (container, NULL); + return FALSE; } static void -extend_selection (GtkCList *clist, - GtkScrollType scroll_type, - gfloat position, - gboolean auto_start_selection) +gtk_clist_draw_focus (GtkWidget *widget) { - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); + GtkCList *clist; - if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) || - clist->selection_mode != GTK_SELECTION_EXTENDED) - return; + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CLIST (widget)); - if (auto_start_selection) - set_anchor (clist, GTK_CLIST_ADD_MODE (clist), clist->focus_row, - clist->focus_row); - else if (clist->anchor == -1) + if (!GTK_WIDGET_DRAWABLE (widget)) return; - move_focus_row (clist, scroll_type, position); - - if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height > - clist->clist_window_height) - gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0); - else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0) - gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0); - - update_extended_selection (clist, clist->focus_row); + clist = GTK_CLIST (widget); + if (clist->focus_row >= 0) + gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, + 0, ROW_TOP_YPIXEL(clist, clist->focus_row), + clist->clist_window_width - 1, + clist->row_height - 1); } -static void -abort_column_resize (GtkCList *clist) +static gint +gtk_clist_focus_in (GtkWidget *widget, + GdkEventFocus *event) { - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); + GtkCList *clist; - if (!GTK_CLIST_IN_DRAG (clist)) - return; + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); - GTK_CLIST_UNSET_FLAG (clist, CLIST_IN_DRAG); - gtk_grab_remove (GTK_WIDGET (clist)); - gdk_pointer_ungrab (GDK_CURRENT_TIME); - clist->drag_pos = -1; + GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS); + GTK_CLIST_UNSET_FLAG (widget, CLIST_CHILD_HAS_FOCUS); - if (clist->x_drag >= 0 && clist->x_drag <= clist->clist_window_width - 1) - draw_xor_line (clist); + clist = GTK_CLIST (widget); - if (GTK_CLIST_ADD_MODE (clist)) + if (clist->selection_mode == GTK_SELECTION_BROWSE && + clist->selection == NULL && clist->focus_row > -1) { - gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_ON_OFF_DASH, 0,0); - gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2); + GList *list; + + list = g_list_nth (clist->row_list, clist->focus_row); + if (list && GTK_CLIST_ROW (list)->selectable) + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], + clist->focus_row, -1, event); + else + gtk_widget_draw_focus (widget); } + else + gtk_widget_draw_focus (widget); + + return FALSE; } static gint -gtk_clist_key_press (GtkWidget * widget, - GdkEventKey * event) +gtk_clist_focus_out (GtkWidget *widget, + GdkEventFocus *event) { + GtkCList *clist; + g_return_val_if_fail (widget != NULL, FALSE); g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE); g_return_val_if_fail (event != NULL, FALSE); - if (GTK_WIDGET_CLASS (parent_class)->key_press_event && - GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event)) - return TRUE; + GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS); + gtk_widget_draw_focus (widget); + + clist = GTK_CLIST (widget); - switch (event->keyval) - { - case GDK_Tab: - case GDK_ISO_Left_Tab: - if (event->state & GDK_SHIFT_MASK) - return gtk_container_focus (GTK_CONTAINER (widget), - GTK_DIR_TAB_BACKWARD); - else - return gtk_container_focus (GTK_CONTAINER (widget), - GTK_DIR_TAB_FORWARD); + if (clist->anchor != -1 && clist->selection_mode == GTK_SELECTION_EXTENDED) + GTK_CLIST_CLASS_FW (widget)->resync_selection (clist, (GdkEvent *) event); - default: - break; - } - return FALSE; } +static void +gtk_clist_set_focus_child (GtkContainer *container, + GtkWidget *child) +{ + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_CLIST (container)); + + if (child) + { + g_return_if_fail (GTK_IS_WIDGET (child)); + GTK_CLIST_SET_FLAG (GTK_CLIST (container), CLIST_CHILD_HAS_FOCUS); + } + + parent_class->set_focus_child (container, child); +} + static gboolean -title_focus (GtkCList * clist, - gint dir) +title_focus (GtkCList *clist, + gint dir) { GtkWidget *focus_child; gboolean return_val = FALSE; @@ -6046,154 +6544,134 @@ title_focus (GtkCList * clist, return return_val; } -static gint -gtk_clist_focus (GtkContainer * container, - GtkDirectionType direction) +/* SCROLLING FUNCTIONS + * move_focus_row + * scroll_horizontal + * scroll_vertical + */ +static void +move_focus_row (GtkCList *clist, + GtkScrollType scroll_type, + gfloat position) { - GtkCList *clist; - GtkWidget *focus_child; - gint old_row; + GtkWidget *widget; - g_return_val_if_fail (container != NULL, FALSE); - g_return_val_if_fail (GTK_IS_CLIST (container), FALSE); + g_return_if_fail (clist != 0); + g_return_if_fail (GTK_IS_CLIST (clist)); - if (!GTK_WIDGET_SENSITIVE (container)) - return FALSE; - - clist = GTK_CLIST (container); - focus_child = container->focus_child; - old_row = clist->focus_row; + widget = GTK_WIDGET (clist); - switch (direction) + switch (scroll_type) { - case GTK_DIR_LEFT: - case GTK_DIR_RIGHT: - if (GTK_CLIST_CHILD_HAS_FOCUS (clist) && - (!focus_child || (focus_child && focus_child != clist->vscrollbar && - focus_child != clist->hscrollbar))) - { - if (title_focus (clist, direction)) - return TRUE; - gtk_container_set_focus_child (container, NULL); - return FALSE; - } - gtk_widget_grab_focus (GTK_WIDGET (container)); - return TRUE; - case GTK_DIR_DOWN: - case GTK_DIR_TAB_FORWARD: - if (GTK_CLIST_CHILD_HAS_FOCUS (clist) && - (!focus_child || (focus_child != clist->vscrollbar && - focus_child != clist->hscrollbar))) - { - gboolean tf = FALSE; - - if (((focus_child && direction == GTK_DIR_DOWN) || - !(tf = title_focus (clist, GTK_DIR_TAB_FORWARD))) - && clist->rows) - { - if (clist->focus_row < 0) - { - clist->focus_row = 0; - - if ((clist->selection_mode == GTK_SELECTION_BROWSE || - clist->selection_mode == GTK_SELECTION_EXTENDED) && - !clist->selection) - select_row (clist, clist->focus_row, -1, NULL); - } - gtk_widget_grab_focus (GTK_WIDGET (container)); - return TRUE; - } - - if (tf) - return TRUE; - } - - GTK_CLIST_SET_FLAG (clist, CLIST_CHILD_HAS_FOCUS); - - if ((!GTK_CLIST_CHILD_HAS_FOCUS (clist) || !focus_child || - (focus_child != clist->vscrollbar && - focus_child != clist->hscrollbar)) && - GTK_WIDGET_VISIBLE (clist->vscrollbar) && - GTK_WIDGET_CAN_FOCUS (clist->vscrollbar)) - { - gtk_widget_grab_focus (clist->vscrollbar); - return TRUE; - } - - if ((!GTK_CLIST_CHILD_HAS_FOCUS (clist) || !focus_child || - focus_child != clist->hscrollbar) && - GTK_WIDGET_VISIBLE (clist->hscrollbar) && - GTK_WIDGET_CAN_FOCUS (clist->hscrollbar)) - { - gtk_widget_grab_focus (clist->hscrollbar); - return TRUE; - } + case GTK_SCROLL_STEP_BACKWARD: + if (clist->focus_row <= 0) + return; + gtk_clist_draw_focus (widget); + clist->focus_row--; + gtk_clist_draw_focus (widget); break; - case GTK_DIR_UP: - case GTK_DIR_TAB_BACKWARD: - if (!focus_child && GTK_CLIST_CHILD_HAS_FOCUS (clist) && - GTK_WIDGET_VISIBLE (clist->hscrollbar) && - GTK_WIDGET_CAN_FOCUS (clist->hscrollbar)) - { - gtk_widget_grab_focus (clist->hscrollbar); - return TRUE; - } - - if ((!focus_child || focus_child == clist->hscrollbar) && - GTK_CLIST_CHILD_HAS_FOCUS (clist) && - GTK_WIDGET_VISIBLE (clist->vscrollbar) && - GTK_WIDGET_CAN_FOCUS (clist->vscrollbar)) - { - gtk_widget_grab_focus (clist->vscrollbar); - return TRUE; - } - - if ((!focus_child || focus_child == clist->hscrollbar || - focus_child == clist->vscrollbar) && - GTK_CLIST_CHILD_HAS_FOCUS (clist) && clist->rows) + case GTK_SCROLL_STEP_FORWARD: + if (clist->focus_row >= clist->rows - 1) + return; + gtk_clist_draw_focus (widget); + clist->focus_row++; + gtk_clist_draw_focus (widget); + break; + case GTK_SCROLL_PAGE_BACKWARD: + if (clist->focus_row <= 0) + return; + gtk_clist_draw_focus (widget); + clist->focus_row = MAX (0, clist->focus_row - + (2 * clist->clist_window_height - + clist->row_height - CELL_SPACING) / + (2 * (clist->row_height + CELL_SPACING))); + gtk_clist_draw_focus (widget); + break; + case GTK_SCROLL_PAGE_FORWARD: + if (clist->focus_row >= clist->rows - 1) + return; + gtk_clist_draw_focus (widget); + clist->focus_row = MIN (clist->rows - 1, clist->focus_row + + (2 * clist->clist_window_height - + clist->row_height - CELL_SPACING) / + (2 * (clist->row_height + CELL_SPACING))); + gtk_clist_draw_focus (widget); + break; + case GTK_SCROLL_JUMP: + if (position >= 0 && position <= 1) { - if (clist->focus_row < 0) - { - clist->focus_row = 0; - if ((clist->selection_mode == GTK_SELECTION_BROWSE || - clist->selection_mode == GTK_SELECTION_EXTENDED) && - !clist->selection) - select_row (clist, clist->focus_row, -1, NULL); - } - gtk_widget_grab_focus (GTK_WIDGET (container)); - return TRUE; + gtk_clist_draw_focus (widget); + clist->focus_row = position * (clist->rows - 1); + gtk_clist_draw_focus (widget); } - - GTK_CLIST_SET_FLAG (clist, CLIST_CHILD_HAS_FOCUS); - - if (title_focus (clist, direction)) - return TRUE; - break; - default: break; } - - gtk_container_set_focus_child (container, NULL); - return FALSE; } -void -gtk_clist_unselect_all (GtkCList * clist) +static void +scroll_horizontal (GtkCList *clist, + GtkScrollType scroll_type, + gfloat position) { - g_return_if_fail (clist != NULL); + gint column = 0; + + g_return_if_fail (clist != 0); g_return_if_fail (GTK_IS_CLIST (clist)); - GTK_CLIST_CLASS_FW (clist)->unselect_all (clist); + if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) + return; + + switch (scroll_type) + { + case GTK_SCROLL_STEP_BACKWARD: + column = COLUMN_FROM_XPIXEL (clist, 0); + if (COLUMN_LEFT_XPIXEL (clist, column) - CELL_SPACING - COLUMN_INSET >= 0 + && column > 0) + column--; + break; + case GTK_SCROLL_STEP_FORWARD: + column = COLUMN_FROM_XPIXEL (clist, clist->clist_window_width); + if (column < 0) + return; + if (COLUMN_LEFT_XPIXEL (clist, column) + clist->column[column].area.width + + CELL_SPACING + COLUMN_INSET - 1 <= clist->clist_window_width && + column < clist->columns - 1) + column++; + break; + case GTK_SCROLL_PAGE_BACKWARD: + case GTK_SCROLL_PAGE_FORWARD: + return; + case GTK_SCROLL_JUMP: + if (position >= 0 && position <= 1) + column = position * (clist->columns - 1); + else + return; + break; + default: + break; + } + + if (COLUMN_LEFT_XPIXEL (clist, column) < CELL_SPACING + COLUMN_INSET) + gtk_clist_moveto (clist, -1, column, 0, 0); + else if (COLUMN_LEFT_XPIXEL (clist, column) + CELL_SPACING + COLUMN_INSET - 1 + + clist->column[column].area.width > clist->clist_window_width) + { + if (column == clist->columns - 1) + gtk_clist_moveto (clist, -1, column, 0, 0); + else + gtk_clist_moveto (clist, -1, column, 0, 1); + } } static void -real_unselect_all (GtkCList * clist) +scroll_vertical (GtkCList *clist, + GtkScrollType scroll_type, + gfloat position) { - GList *list; - gint i; - + gint old_focus_row; + g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); @@ -6202,169 +6680,164 @@ real_unselect_all (GtkCList * clist) switch (clist->selection_mode) { + case GTK_SELECTION_EXTENDED: + if (clist->anchor >= 0) + return; case GTK_SELECTION_BROWSE: - if (clist->focus_row >= 0) + + old_focus_row = clist->focus_row; + move_focus_row (clist, scroll_type, position); + + if (old_focus_row != clist->focus_row) { - select_row (clist, clist->focus_row, -1, NULL); - return; + if (clist->selection_mode == GTK_SELECTION_BROWSE) + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], + old_focus_row, -1, NULL); + else if (!GTK_CLIST_ADD_MODE (clist)) + { + gtk_clist_unselect_all (clist); + clist->undo_anchor = old_focus_row; + } } - break; - - case GTK_SELECTION_EXTENDED: - g_list_free (clist->undo_selection); - g_list_free (clist->undo_unselection); - clist->undo_selection = NULL; - clist->undo_unselection = NULL; - clist->anchor = -1; - clist->drag_pos = -1; - clist->undo_anchor = clist->focus_row; + switch (gtk_clist_row_is_visible (clist, clist->focus_row)) + { + case GTK_VISIBILITY_NONE: + if (old_focus_row != clist->focus_row && + !(clist->selection_mode == GTK_SELECTION_EXTENDED && + GTK_CLIST_ADD_MODE (clist))) + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], + clist->focus_row, -1, NULL); + switch (scroll_type) + { + case GTK_SCROLL_STEP_BACKWARD: + case GTK_SCROLL_PAGE_BACKWARD: + gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0); + break; + case GTK_SCROLL_STEP_FORWARD: + case GTK_SCROLL_PAGE_FORWARD: + gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0); + break; + case GTK_SCROLL_JUMP: + gtk_clist_moveto (clist, clist->focus_row, -1, 0.5, 0); + break; + default: + break; + } + break; + case GTK_VISIBILITY_PARTIAL: + switch (scroll_type) + { + case GTK_SCROLL_STEP_BACKWARD: + case GTK_SCROLL_PAGE_BACKWARD: + gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0); + break; + case GTK_SCROLL_STEP_FORWARD: + case GTK_SCROLL_PAGE_FORWARD: + gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0); + break; + case GTK_SCROLL_JUMP: + gtk_clist_moveto (clist, clist->focus_row, -1, 0.5, 0); + break; + default: + break; + } + default: + if (old_focus_row != clist->focus_row && + !(clist->selection_mode == GTK_SELECTION_EXTENDED && + GTK_CLIST_ADD_MODE (clist))) + gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], + clist->focus_row, -1, NULL); + break; + } break; - default: - break; - } - - list = clist->selection; + move_focus_row (clist, scroll_type, position); - while (list) - { - i = GPOINTER_TO_INT (list->data); - list = list->next; - unselect_row (clist, i, -1, NULL); + if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height > + clist->clist_window_height) + gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0); + else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0) + gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0); + break; } } +/* PUBLIC SORTING FUNCTIONS + * gtk_clist_sort + * gtk_clist_set_compare_func + * gtk_clist_set_auto_sort + * gtk_clist_set_sort_type + * gtk_clist_set_sort_column + */ void -gtk_clist_select_all (GtkCList * clist) +gtk_clist_sort (GtkCList *clist) { g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); - GTK_CLIST_CLASS_FW (clist)->select_all (clist); + GTK_CLIST_CLASS_FW (clist)->sort_list (clist); } -static void -real_select_all (GtkCList * clist) +void +gtk_clist_set_compare_func (GtkCList *clist, + GtkCListCompareFunc cmp_func) { - GList *list; - gint i; - g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); - if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) - return; - - switch (clist->selection_mode) - { - case GTK_SELECTION_SINGLE: - case GTK_SELECTION_BROWSE: - return; - - case GTK_SELECTION_EXTENDED: - g_list_free (clist->undo_selection); - g_list_free (clist->undo_unselection); - clist->undo_selection = NULL; - clist->undo_unselection = NULL; - - if (clist->rows && - ((GtkCListRow *) (clist->row_list->data))->state != - GTK_STATE_SELECTED) - fake_toggle_row (clist, 0); - - clist->anchor_state = GTK_STATE_SELECTED; - clist->anchor = 0; - clist->drag_pos = 0; - clist->undo_anchor = clist->focus_row; - update_extended_selection (clist, clist->rows); - GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL); - return; - - case GTK_SELECTION_MULTIPLE: - for (i = 0, list = clist->row_list; list; i++, list = list->next) - { - if (((GtkCListRow *)(list->data))->state == GTK_STATE_NORMAL) - gtk_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], - i, -1, NULL); - } - return; - } + clist->compare = (cmp_func) ? cmp_func : default_compare; } -static void -fake_unselect_all (GtkCList * clist, - gint row) +void +gtk_clist_set_auto_sort (GtkCList *clist, + gboolean auto_sort) { - GList *list; - GList *work; - gint i; - - if (row >= 0 && (work = g_list_nth (clist->row_list, row))) - { - if (GTK_CLIST_ROW (work)->state == GTK_STATE_NORMAL && - GTK_CLIST_ROW (work)->selectable) - { - GTK_CLIST_ROW (work)->state = GTK_STATE_SELECTED; - - if (!GTK_CLIST_FROZEN (clist) && - gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE) - GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, - GTK_CLIST_ROW (work)); - } - } - - clist->undo_selection = clist->selection; - clist->selection = NULL; - clist->selection_end = NULL; + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); - for (list = clist->undo_selection; list; list = list->next) + if (GTK_CLIST_AUTO_SORT (clist) && !auto_sort) + GTK_CLIST_UNSET_FLAG (clist, CLIST_AUTO_SORT); + else if (!GTK_CLIST_AUTO_SORT (clist) && auto_sort) { - if ((i = GPOINTER_TO_INT (list->data)) == row || - !(work = g_list_nth (clist->row_list, i))) - continue; - - GTK_CLIST_ROW (work)->state = GTK_STATE_NORMAL; - if (!GTK_CLIST_FROZEN (clist) && - gtk_clist_row_is_visible (clist, i) != GTK_VISIBILITY_NONE) - GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, i, - GTK_CLIST_ROW (work)); + GTK_CLIST_SET_FLAG (clist, CLIST_AUTO_SORT); + gtk_clist_sort (clist); } } -static void -fake_toggle_row (GtkCList *clist, - gint row) +void +gtk_clist_set_sort_type (GtkCList *clist, + GtkSortType sort_type) { - GList *work; - - if (!(work = g_list_nth (clist->row_list, row))|| - !GTK_CLIST_ROW (work)->selectable) - return; - - if (GTK_CLIST_ROW (work)->state == GTK_STATE_NORMAL) - clist->anchor_state = GTK_CLIST_ROW (work)->state = GTK_STATE_SELECTED; - else - clist->anchor_state = GTK_CLIST_ROW (work)->state = GTK_STATE_NORMAL; + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); - if (!GTK_CLIST_FROZEN (clist) && - gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE) - GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, - GTK_CLIST_ROW (work)); + clist->sort_type = sort_type; } -static GList * -selection_find (GtkCList *clist, - gint row_number, - GList *row_list_element) +void +gtk_clist_set_sort_column (GtkCList *clist, + gint column) { - return g_list_find (clist->selection, GINT_TO_POINTER (row_number)); + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CLIST (clist)); + + if (column < 0 || column >= clist->columns) + return; + + clist->sort_column = column; } +/* PRIVATE SORTING FUNCTIONS + * default_compare + * real_sort_list + * gtk_clist_merge + * gtk_clist_mergesort + */ static gint -default_compare (GtkCList *clist, - gconstpointer ptr1, - gconstpointer ptr2) +default_compare (GtkCList *clist, + gconstpointer ptr1, + gconstpointer ptr2) { char *text1 = NULL; char *text2 = NULL; @@ -6402,56 +6875,59 @@ default_compare (GtkCList *clist, if (!text1) return -1; - return strcmp (text1, text2); -} - -void -gtk_clist_set_compare_func (GtkCList *clist, - GtkCListCompareFunc cmp_func) -{ - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); - - clist->compare = (cmp_func) ? cmp_func : default_compare; + return strcmp (text1, text2); } -void -gtk_clist_set_auto_sort (GtkCList *clist, - gboolean auto_sort) +static void +real_sort_list (GtkCList *clist) { + GList *list; + GList *work; + gint i; + gboolean thaw = FALSE; + g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CLIST (clist)); - - if (GTK_CLIST_AUTO_SORT (clist) && !auto_sort) - GTK_CLIST_UNSET_FLAG (clist, CLIST_AUTO_SORT); - else if (!GTK_CLIST_AUTO_SORT (clist) && auto_sort) + + if (clist->rows <= 1) + return; + + if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) + return; + + if (clist->anchor != -1 && clist->selection_mode == GTK_SELECTION_EXTENDED) { - GTK_CLIST_SET_FLAG (clist, CLIST_AUTO_SORT); - gtk_clist_sort (clist); + GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL); + g_list_free (clist->undo_selection); + g_list_free (clist->undo_unselection); + clist->undo_selection = NULL; + clist->undo_unselection = NULL; + } + + if (!GTK_CLIST_FROZEN (clist)) + { + gtk_clist_freeze (clist); + thaw = TRUE; } -} -void -gtk_clist_set_sort_type (GtkCList *clist, - GtkSortType sort_type) -{ - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); - - clist->sort_type = sort_type; -} + clist->row_list = gtk_clist_mergesort (clist, clist->row_list, clist->rows); -void -gtk_clist_set_sort_column (GtkCList *clist, - gint column) -{ - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); + work = clist->selection; - if (column < 0 || column >= clist->columns) - return; + for (i = 0, list = clist->row_list; i < clist->rows; i++, list = list->next) + { + if (GTK_CLIST_ROW (list)->state == GTK_STATE_SELECTED) + { + work->data = GINT_TO_POINTER (i); + work = work->next; + } + + if (i == clist->rows - 1) + clist->row_list_end = list; + } - clist->sort_column = column; + if (thaw) + gtk_clist_thaw (clist); } static GList * @@ -6537,195 +7013,3 @@ gtk_clist_mergesort (GtkCList *clist, gtk_clist_mergesort (clist, half, num - num / 2)); } } - -void -gtk_clist_sort (GtkCList *clist) -{ - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); - - GTK_CLIST_CLASS_FW (clist)->sort_list (clist); -} - -static void -real_sort_list (GtkCList *clist) -{ - GList *list; - GList *work; - gint i; - gboolean thaw = FALSE; - - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); - - if (clist->rows <= 1) - return; - - if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (clist)) - return; - - if (clist->anchor != -1 && clist->selection_mode == GTK_SELECTION_EXTENDED) - { - GTK_CLIST_CLASS_FW (clist)->resync_selection (clist, NULL); - g_list_free (clist->undo_selection); - g_list_free (clist->undo_unselection); - clist->undo_selection = NULL; - clist->undo_unselection = NULL; - } - - if (!GTK_CLIST_FROZEN (clist)) - { - gtk_clist_freeze (clist); - thaw = TRUE; - } - - clist->row_list = gtk_clist_mergesort (clist, clist->row_list, clist->rows); - - work = clist->selection; - - for (i = 0, list = clist->row_list; i < clist->rows; i++, list = list->next) - { - if (GTK_CLIST_ROW (list)->state == GTK_STATE_SELECTED) - { - work->data = GINT_TO_POINTER (i); - work = work->next; - } - - if (i == clist->rows - 1) - clist->row_list_end = list; - } - - if (thaw) - gtk_clist_thaw (clist); -} - -/* gtk_clist_set_cell_style - * gtk_clist_get_cell_style - * gtk_clist_set_row_style - * gtk_clist_get_row_style - */ - -void -gtk_clist_set_cell_style (GtkCList *clist, - gint row, - gint column, - GtkStyle *style) -{ - GtkCListRow *clist_row; - - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); - - if (row < 0 || row >= clist->rows || column < 0 || column >= clist->columns) - return; - - clist_row = (g_list_nth (clist->row_list, row))->data; - - if (clist_row->cell[column].style == style) - return; - - if (clist_row->cell[column].style) - { - if (GTK_WIDGET_REALIZED (clist)) - gtk_style_detach (clist_row->cell[column].style); - gtk_style_unref (clist_row->cell[column].style); - } - - clist_row->cell[column].style = style; - - if (clist_row->cell[column].style) - { - gtk_style_ref (clist_row->cell[column].style); - - if (GTK_WIDGET_REALIZED (clist)) - clist_row->cell[column].style = - gtk_style_attach (clist_row->cell[column].style, - clist->clist_window); - } - - /* redraw the list if it's not frozen */ - if (!GTK_CLIST_FROZEN (clist)) - { - if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE) - GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row); - } -} - -GtkStyle * -gtk_clist_get_cell_style (GtkCList *clist, - gint row, - gint column) -{ - GtkCListRow *clist_row; - - g_return_val_if_fail (clist != NULL, NULL); - g_return_val_if_fail (GTK_IS_CLIST (clist), NULL); - - if (row < 0 || row >= clist->rows || column < 0 || column >= clist->columns) - return NULL; - - clist_row = (g_list_nth (clist->row_list, row))->data; - - return clist_row->cell[column].style; -} - -void -gtk_clist_set_row_style (GtkCList *clist, - gint row, - GtkStyle *style) -{ - GtkCListRow *clist_row; - - g_return_if_fail (clist != NULL); - g_return_if_fail (GTK_IS_CLIST (clist)); - - if (row < 0 || row >= clist->rows) - return; - - clist_row = (g_list_nth (clist->row_list, row))->data; - - if (clist_row->style == style) - return; - - if (clist_row->style) - { - if (GTK_WIDGET_REALIZED (clist)) - gtk_style_detach (clist_row->style); - gtk_style_unref (clist_row->style); - } - - clist_row->style = style; - - if (clist_row->style) - { - gtk_style_ref (clist_row->style); - - if (GTK_WIDGET_REALIZED (clist)) - clist_row->style = gtk_style_attach (clist_row->style, - clist->clist_window); - } - - /* redraw the list if it's not frozen */ - if (!GTK_CLIST_FROZEN (clist)) - { - if (gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE) - GTK_CLIST_CLASS_FW (clist)->draw_row (clist, NULL, row, clist_row); - } -} - -GtkStyle * -gtk_clist_get_row_style (GtkCList *clist, - gint row) -{ - GtkCListRow *clist_row; - - g_return_val_if_fail (clist != NULL, NULL); - g_return_val_if_fail (GTK_IS_CLIST (clist), NULL); - - if (row < 0 || row >= clist->rows) - return NULL; - - clist_row = (g_list_nth (clist->row_list, row))->data; - - return clist_row->style; -} diff --git a/gtk/gtkclist.h b/gtk/gtkclist.h index 0e56a78923..bbc23c762d 100644 --- a/gtk/gtkclist.h +++ b/gtk/gtkclist.h @@ -36,15 +36,16 @@ extern "C" { /* clist flags */ enum { - GTK_CLIST_FROZEN = 1 << 0, - GTK_CLIST_IN_DRAG = 1 << 1, - GTK_CLIST_DRAG_SELECTION = 1 << 2, - GTK_CLIST_ROW_HEIGHT_SET = 1 << 3, - GTK_CLIST_SHOW_TITLES = 1 << 4, - GTK_CLIST_CONSTRUCTED = 1 << 5, - GTK_CLIST_CHILD_HAS_FOCUS = 1 << 6, - GTK_CLIST_ADD_MODE = 1 << 7, - GTK_CLIST_AUTO_SORT = 1 << 8 + GTK_CLIST_FROZEN = 1 << 0, + GTK_CLIST_IN_DRAG = 1 << 1, + GTK_CLIST_DRAG_SELECTION = 1 << 2, + GTK_CLIST_ROW_HEIGHT_SET = 1 << 3, + GTK_CLIST_SHOW_TITLES = 1 << 4, + GTK_CLIST_CONSTRUCTED = 1 << 5, + GTK_CLIST_CHILD_HAS_FOCUS = 1 << 6, + GTK_CLIST_ADD_MODE = 1 << 7, + GTK_CLIST_AUTO_SORT = 1 << 8, + GTK_CLIST_AUTO_RESIZE_BLOCKED = 1 << 9 }; /* cell types */ @@ -76,6 +77,7 @@ typedef enum #define GTK_CLIST_DRAG_SELECTION(clist) (GTK_CLIST_FLAGS (clist) & GTK_CLIST_DRAG_SELECTION) #define GTK_CLIST_ADD_MODE(clist) (GTK_CLIST_FLAGS (clist) & GTK_CLIST_ADD_MODE) #define GTK_CLIST_AUTO_SORT(clist) (GTK_CLIST_FLAGS (clist) & GTK_CLIST_AUTO_SORT) +#define GTK_CLIST_AUTO_RESIZE_BLOCKED(clist) (GTK_CLIST_FLAGS (clist) & GTK_CLIST_AUTO_RESIZE_BLOCKED) #define GTK_CLIST_ROW(_glist_) ((GtkCListRow *)((_glist_)->data)) @@ -191,64 +193,68 @@ struct _GtkCListClass { GtkContainerClass parent_class; - void (*select_row) (GtkCList *clist, - gint row, - gint column, - GdkEvent *event); - void (*unselect_row) (GtkCList *clist, - gint row, - gint column, - GdkEvent *event); - void (*click_column) (GtkCList *clist, - gint column); - void (*resize_column) (GtkCList *clist, - gint column, - gint width); - void (*toggle_focus_row) (GtkCList *clist); - void (*select_all) (GtkCList *clist); - void (*unselect_all) (GtkCList *clist); - void (*undo_selection) (GtkCList *clist); - void (*start_selection) (GtkCList *clist); - void (*end_selection) (GtkCList *clist); - void (*extend_selection) (GtkCList *clist, - GtkScrollType scroll_type, - gfloat position, - gboolean auto_start_selection); - void (*scroll_horizontal) (GtkCList *clist, - GtkScrollType scroll_type, - gfloat position); - void (*scroll_vertical) (GtkCList *clist, - GtkScrollType scroll_type, - gfloat position); - void (*toggle_add_mode) (GtkCList *clist); - void (*abort_column_resize) (GtkCList *clist); - void (*resync_selection) (GtkCList *clist, - GdkEvent *event); - GList* (*selection_find) (GtkCList *clist, - gint row_number, - GList *row_list_element); - void (*draw_row) (GtkCList *clist, - GdkRectangle *area, - gint row, - GtkCListRow *clist_row); - void (*clear) (GtkCList *clist); - void (*fake_unselect_all) (GtkCList *clist, - gint row); - void (*sort_list) (GtkCList *clist); - gint (*insert_row) (GtkCList *clist, - gint row, - gchar *text[]); - void (*remove_row) (GtkCList *clist, - gint row); - void (*set_cell_contents) (GtkCList *clist, - GtkCListRow *clist_row, - gint column, - GtkCellType type, - const gchar *text, - guint8 spacing, - GdkPixmap *pixmap, - GdkBitmap *mask); - + void (*select_row) (GtkCList *clist, + gint row, + gint column, + GdkEvent *event); + void (*unselect_row) (GtkCList *clist, + gint row, + gint column, + GdkEvent *event); + void (*click_column) (GtkCList *clist, + gint column); + void (*resize_column) (GtkCList *clist, + gint column, + gint width); + void (*toggle_focus_row) (GtkCList *clist); + void (*select_all) (GtkCList *clist); + void (*unselect_all) (GtkCList *clist); + void (*undo_selection) (GtkCList *clist); + void (*start_selection) (GtkCList *clist); + void (*end_selection) (GtkCList *clist); + void (*extend_selection) (GtkCList *clist, + GtkScrollType scroll_type, + gfloat position, + gboolean auto_start_selection); + void (*scroll_horizontal) (GtkCList *clist, + GtkScrollType scroll_type, + gfloat position); + void (*scroll_vertical) (GtkCList *clist, + GtkScrollType scroll_type, + gfloat position); + void (*toggle_add_mode) (GtkCList *clist); + void (*abort_column_resize) (GtkCList *clist); + void (*resync_selection) (GtkCList *clist, + GdkEvent *event); + GList* (*selection_find) (GtkCList *clist, + gint row_number, + GList *row_list_element); + void (*draw_row) (GtkCList *clist, + GdkRectangle *area, + gint row, + GtkCListRow *clist_row); + void (*clear) (GtkCList *clist); + void (*fake_unselect_all) (GtkCList *clist, + gint row); + void (*sort_list) (GtkCList *clist); + gint (*insert_row) (GtkCList *clist, + gint row, + gchar *text[]); + void (*remove_row) (GtkCList *clist, + gint row); + void (*set_cell_contents) (GtkCList *clist, + GtkCListRow *clist_row, + gint column, + GtkCellType type, + const gchar *text, + guint8 spacing, + GdkPixmap *pixmap, + GdkBitmap *mask); + void (*cell_size_request) (GtkCList *clist, + GtkCListRow *clist_row, + gint column, + GtkRequisition *requisition); + gint scrollbar_spacing; }; @@ -265,9 +271,10 @@ struct _GtkCListColumn gint max_width; GtkJustification justification; - gint visible : 1; - gint width_set : 1; - gint resizeable : 1; + guint visible : 1; + guint width_set : 1; + guint resizeable : 1; + guint auto_resize : 1; }; struct _GtkCListRow @@ -283,9 +290,9 @@ struct _GtkCListRow gpointer data; GtkDestroyNotify destroy; - gint fg_set : 1; - gint bg_set : 1; - gint selectable : 1; + guint fg_set : 1; + guint bg_set : 1; + guint selectable : 1; }; /* Cell Structures */ @@ -381,10 +388,14 @@ GtkWidget *gtk_clist_new (gint columns); GtkWidget *gtk_clist_new_with_titles (gint columns, gchar *titles[]); -/* set the border style of the clist */ +/* deprecated function, use gtk_clist_set_shadow_type instead. */ void gtk_clist_set_border (GtkCList *clist, GtkShadowType border); +/* set the border style of the clist */ +void gtk_clist_set_shadow_type (GtkCList *clist, + GtkShadowType type); + /* set the clist's selection mode */ void gtk_clist_set_selection_mode (GtkCList *clist, GtkSelectionMode mode); @@ -444,6 +455,15 @@ void gtk_clist_set_column_resizeable (GtkCList *clist, gint column, gboolean resizeable); +/* resize column automatically to its optimal width */ +void gtk_clist_set_column_auto_resize (GtkCList *clist, + gint column, + gboolean auto_resize); + +/* return the optimal column width, i.e. maximum of all cell widths */ +gint gtk_clist_optimal_column_width (GtkCList *clist, + gint column); + /* set the pixel width of a column; this is a necessary step in * creating a CList because otherwise the column width is chozen from * the width of the column title, which will never be right @@ -546,20 +566,20 @@ void gtk_clist_set_background (GtkCList *clist, /* set / get cell styles */ void gtk_clist_set_cell_style (GtkCList *clist, - gint row, - gint column, + gint row, + gint column, GtkStyle *style); GtkStyle *gtk_clist_get_cell_style (GtkCList *clist, - gint row, - gint column); + gint row, + gint column); void gtk_clist_set_row_style (GtkCList *clist, - gint row, + gint row, GtkStyle *style); GtkStyle *gtk_clist_get_row_style (GtkCList *clist, - gint row); + gint row); /* this sets a horizontal and vertical shift for drawing * the contents of a cell; it can be positive or negitive; diff --git a/gtk/gtkctree.c b/gtk/gtkctree.c index 5ad5744dad..a3799e5c87 100644 --- a/gtk/gtkctree.c +++ b/gtk/gtkctree.c @@ -221,7 +221,14 @@ static void real_sort_list (GtkCList *clist); static void set_mouse_cursor (GtkCTree *ctree, gboolean enable); static void check_cursor (GtkCTree *ctree); - +static void cell_size_request (GtkCList *clist, + GtkCListRow *clist_row, + gint column, + GtkRequisition *requisition); +static void column_auto_resize (GtkCList *clist, + GtkCListRow *clist_row, + gint column, + gint old_width); enum { @@ -369,6 +376,7 @@ gtk_ctree_class_init (GtkCTreeClass *klass) clist_class->remove_row = real_remove_row; clist_class->sort_list = real_sort_list; clist_class->set_cell_contents = set_cell_contents; + clist_class->cell_size_request = cell_size_request; klass->tree_select_row = real_tree_select; klass->tree_unselect_row = real_tree_unselect; @@ -2521,6 +2529,7 @@ real_tree_move (GtkCTree *ctree, GtkCList *clist; GtkCTreeNode *work; gboolean thaw = FALSE; + gboolean visible = FALSE; g_return_if_fail (ctree != NULL); g_return_if_fail (node != NULL); @@ -2537,6 +2546,8 @@ real_tree_move (GtkCTree *ctree, clist = GTK_CLIST (ctree); + visible = gtk_ctree_is_viewable (ctree, node); + if (clist->selection_mode == GTK_SELECTION_EXTENDED) { if (clist->anchor != -1) @@ -2589,6 +2600,13 @@ real_tree_move (GtkCTree *ctree, clist->undo_anchor = clist->focus_row; } + if (clist->column[ctree->tree_column].auto_resize && + !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist) && + (visible || gtk_ctree_is_viewable (ctree, node))) + gtk_clist_set_column_width + (clist, ctree->tree_column, + gtk_clist_optimal_column_width (clist, ctree->tree_column)); + if (thaw) gtk_clist_thaw (clist); } @@ -2642,6 +2660,8 @@ real_tree_expand (GtkCTree *ctree, { GtkCList *clist; GtkCTreeNode *work; + GtkRequisition requisition; + gboolean visible; gint level; g_return_if_fail (ctree != NULL); @@ -2658,6 +2678,14 @@ real_tree_expand (GtkCTree *ctree, GTK_CTREE_ROW (node)->expanded = TRUE; level = GTK_CTREE_ROW (node)->level; + visible = gtk_ctree_is_viewable (ctree, node); + /* get cell width if tree_column is auto resized */ + if (visible && clist->column[ctree->tree_column].auto_resize && + !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist)) + GTK_CLIST_CLASS_FW (clist)->cell_size_request + (clist, >K_CTREE_ROW (node)->row, ctree->tree_column, &requisition); + + /* unref/unset closed pixmap */ if (GTK_CELL_PIXTEXT (GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap) { @@ -2679,6 +2707,7 @@ real_tree_expand (GtkCTree *ctree, } } + /* set/ref opened pixmap */ if (GTK_CTREE_ROW (node)->pixmap_opened) { GTK_CELL_PIXTEXT @@ -2691,15 +2720,37 @@ real_tree_expand (GtkCTree *ctree, gdk_pixmap_ref (GTK_CTREE_ROW (node)->mask_opened); } + work = GTK_CTREE_ROW (node)->children; if (work) { + GList *list; + gint *cell_width = NULL; gint tmp = 0; gint row; - GList *list; + gint i; + if (visible && !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist)) + { + cell_width = g_new0 (gint, clist->columns); + if (clist->column[ctree->tree_column].auto_resize) + cell_width[ctree->tree_column] = requisition.width; + } + while (GTK_CTREE_NODE_NEXT (work)) { + if (visible && !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist)) + { + /* search maximum cell widths of auto_resize columns */ + for (i = 0; i < clist->columns; i++) + if (clist->column[i].auto_resize) + { + GTK_CLIST_CLASS_FW (clist)->cell_size_request + (clist, >K_CTREE_ROW (work)->row, i, &requisition); + cell_width[i] = MAX (requisition.width, cell_width[i]); + } + } + work = GTK_CTREE_NODE_NEXT (work); tmp++; } @@ -2718,16 +2769,29 @@ real_tree_expand (GtkCTree *ctree, list = (GList *)node; list->next = (GList *)(GTK_CTREE_ROW (node)->children); - if (gtk_ctree_is_viewable (ctree, node)) + if (visible) { + /* resize auto_resize columns if needed */ + for (i = 0; i < clist->columns; i++) + if (clist->column[i].auto_resize && + cell_width[i] > clist->column[i].width) + gtk_clist_set_column_width (clist, i, cell_width[i]); + g_free (cell_width); + + /* update focus_row position */ row = g_list_position (clist->row_list, (GList *)node); if (row < clist->focus_row) clist->focus_row += tmp + 1; + clist->rows += tmp + 1; if (!GTK_CLIST_FROZEN (ctree)) gtk_clist_thaw (clist); } } + else if (visible && clist->column[ctree->tree_column].auto_resize) + /* resize tree_column if needed */ + column_auto_resize (clist, >K_CTREE_ROW (node)->row, ctree->tree_column, + requisition.width); } static void @@ -2736,12 +2800,15 @@ real_tree_collapse (GtkCTree *ctree, { GtkCList *clist; GtkCTreeNode *work; + GtkRequisition requisition; + gboolean visible; gint level; g_return_if_fail (ctree != NULL); g_return_if_fail (GTK_IS_CTREE (ctree)); - if (!node || !GTK_CTREE_ROW (node)->expanded ||GTK_CTREE_ROW (node)->is_leaf) + if (!node || !GTK_CTREE_ROW (node)->expanded || + GTK_CTREE_ROW (node)->is_leaf) return; clist = GTK_CLIST (ctree); @@ -2752,6 +2819,14 @@ real_tree_collapse (GtkCTree *ctree, GTK_CTREE_ROW (node)->expanded = FALSE; level = GTK_CTREE_ROW (node)->level; + visible = gtk_ctree_is_viewable (ctree, node); + /* get cell width if tree_column is auto resized */ + if (visible && clist->column[ctree->tree_column].auto_resize && + !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist)) + GTK_CLIST_CLASS_FW (clist)->cell_size_request + (clist, >K_CTREE_ROW (node)->row, ctree->tree_column, &requisition); + + /* unref/unset opened pixmap */ if (GTK_CELL_PIXTEXT (GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap) { @@ -2773,6 +2848,7 @@ real_tree_collapse (GtkCTree *ctree, } } + /* set/ref closed pixmap */ if (GTK_CTREE_ROW (node)->pixmap_closed) { GTK_CELL_PIXTEXT @@ -2814,8 +2890,35 @@ real_tree_collapse (GtkCTree *ctree, clist->row_list_end = (GList *)node; } - if (gtk_ctree_is_viewable (ctree, node)) + if (visible) { + /* resize auto_resize columns if needed */ + if (!GTK_CLIST_AUTO_RESIZE_BLOCKED (clist)) + { + GList *list; + gint new_width; + gint i; + + for (i = 0; i < clist->columns; i++) + if (clist->column[i].auto_resize) + { + /* run a "gtk_clist_optimal_column_width" but break, if + * the column doesn't shrink */ + new_width = 0; + for (list = clist->row_list; list; list = list->next) + { + GTK_CLIST_CLASS_FW (clist)->cell_size_request + (clist, GTK_CLIST_ROW (list), i, &requisition); + new_width = MAX (new_width, requisition.width); + if (new_width == clist->column[i].width) + break; + } + + if (new_width < clist->column[i].width) + gtk_clist_set_column_width (clist, i, new_width); + } + } + row = g_list_position (clist->row_list, (GList *)node); if (row < clist->focus_row) clist->focus_row -= tmp; @@ -2824,6 +2927,133 @@ real_tree_collapse (GtkCTree *ctree, gtk_clist_thaw (clist); } } + else if (visible && clist->column[ctree->tree_column].auto_resize && + !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist)) + /* resize tree_column if needed */ + column_auto_resize (clist, >K_CTREE_ROW (node)->row, ctree->tree_column, + requisition.width); + +} + +static void +column_auto_resize (GtkCList *clist, + GtkCListRow *clist_row, + gint column, + gint old_width) +{ + /* resize column if needed for auto_resize */ + GtkRequisition requisition; + + if (!clist->column[column].auto_resize || + GTK_CLIST_AUTO_RESIZE_BLOCKED (clist)) + return; + + GTK_CLIST_CLASS_FW (clist)->cell_size_request (clist, clist_row, + column, &requisition); + + if (requisition.width > clist->column[column].width) + { + if (clist->column[column].max_width < 0) + gtk_clist_set_column_width (clist, column, requisition.width); + else if (clist->column[column].max_width > clist->column[column].width) + gtk_clist_set_column_width (clist, column, + MIN (requisition.width, + clist->column[column].max_width)); + } + else if (requisition.width < old_width && + old_width == clist->column[column].width) + { + GList *list; + gint new_width = 0; + + /* run a "gtk_clist_optimal_column_width" but break, if + * the column doesn't shrink */ + for (list = clist->row_list; list; list = list->next) + { + GTK_CLIST_CLASS_FW (clist)->cell_size_request + (clist, GTK_CLIST_ROW (list), column, &requisition); + new_width = MAX (new_width, requisition.width); + if (new_width == clist->column[column].width) + break; + } + if (new_width < clist->column[column].width) + gtk_clist_set_column_width + (clist, column, MAX (new_width, clist->column[column].min_width)); + } +} + +static void +cell_size_request (GtkCList *clist, + GtkCListRow *clist_row, + gint column, + GtkRequisition *requisition) +{ + GtkCTree *ctree; + GtkStyle *style; + gint width; + gint height; + + g_return_if_fail (clist != NULL); + g_return_if_fail (GTK_IS_CTREE (clist)); + g_return_if_fail (requisition != NULL); + + ctree = GTK_CTREE (clist); + + get_cell_style (clist, clist_row, GTK_STATE_PRELIGHT, column, &style, + NULL, NULL); + + switch (clist_row->cell[column].type) + { + case GTK_CELL_TEXT: + requisition->width = + gdk_string_width (style->font, + GTK_CELL_TEXT (clist_row->cell[column])->text); + requisition->height = style->font->ascent + style->font->descent; + break; + case GTK_CELL_PIXTEXT: + gdk_window_get_size (GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap, + &width, &height); + requisition->width = width + + GTK_CELL_PIXTEXT (clist_row->cell[column])->spacing + + gdk_string_width (style->font, + GTK_CELL_TEXT (clist_row->cell[column])->text); + + requisition->height = MAX (style->font->ascent + style->font->descent, + height); + if (column == ctree->tree_column) + { + requisition->width += (ctree->tree_spacing + ctree->tree_indent * + (((GtkCTreeRow *) clist_row)->level - 1)); + switch (ctree->expander_style) + { + case GTK_CTREE_EXPANDER_NONE: + break; + case GTK_CTREE_EXPANDER_TRIANGLE: + requisition->width += PM_SIZE + 3; + break; + case GTK_CTREE_EXPANDER_SQUARE: + case GTK_CTREE_EXPANDER_CIRCULAR: + requisition->width += PM_SIZE + 1; + break; + } + if (ctree->line_style == GTK_CTREE_LINES_TABBED) + requisition->width += 3; + } + break; + case GTK_CELL_PIXMAP: + gdk_window_get_size (GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap, + &width, &height); + requisition->width = width; + requisition->height = height; + break; + default: + requisition->width = 0; + requisition->height = 0; + break; + } + + requisition->width += clist_row->cell[column].horizontal; + requisition->height += clist_row->cell[column].vertical; } static void @@ -2836,7 +3066,9 @@ set_cell_contents (GtkCList *clist, GdkPixmap *pixmap, GdkBitmap *mask) { + gboolean visible = FALSE; GtkCTree *ctree; + GtkRequisition requisition; g_return_if_fail (clist != NULL); g_return_if_fail (GTK_IS_CTREE (clist)); @@ -2844,6 +3076,21 @@ set_cell_contents (GtkCList *clist, ctree = GTK_CTREE (clist); + if (clist->column[column].auto_resize && + !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist)) + { + GtkCTreeNode *parent; + + parent = ((GtkCTreeRow *)clist_row)->parent; + if (!parent || (parent && GTK_CTREE_ROW (parent)->expanded && + gtk_ctree_is_viewable (ctree, parent))) + { + visible = TRUE; + GTK_CLIST_CLASS_FW (clist)->cell_size_request (clist, clist_row, + column, &requisition); + } + } + switch (clist_row->cell[column].type) { case GTK_CELL_EMPTY: @@ -2852,13 +3099,11 @@ set_cell_contents (GtkCList *clist, case GTK_CELL_TEXT: g_free (GTK_CELL_TEXT (clist_row->cell[column])->text); break; - case GTK_CELL_PIXMAP: gdk_pixmap_unref (GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap); if (GTK_CELL_PIXMAP (clist_row->cell[column])->mask) gdk_bitmap_unref (GTK_CELL_PIXMAP (clist_row->cell[column])->mask); break; - case GTK_CELL_PIXTEXT: if (GTK_CELL_PIXTEXT (clist_row->cell[column])->text) g_free (GTK_CELL_PIXTEXT (clist_row->cell[column])->text); @@ -2871,7 +3116,6 @@ set_cell_contents (GtkCList *clist, (GTK_CELL_PIXTEXT (clist_row->cell[column])->mask); } break; - case GTK_CELL_WIDGET: /* unimplimented */ break; @@ -2893,7 +3137,6 @@ set_cell_contents (GtkCList *clist, GTK_CELL_TEXT (clist_row->cell[column])->text = g_strdup (text); } break; - case GTK_CELL_PIXMAP: if (pixmap) { @@ -2903,7 +3146,6 @@ set_cell_contents (GtkCList *clist, GTK_CELL_PIXMAP (clist_row->cell[column])->mask = mask; } break; - case GTK_CELL_PIXTEXT: if (column == ctree->tree_column) { @@ -2933,10 +3175,12 @@ set_cell_contents (GtkCList *clist, GTK_CELL_PIXTEXT (clist_row->cell[column])->mask = mask; } break; - default: break; } + + if (visible) + column_auto_resize (clist, clist_row, column, requisition.width); } static void @@ -3654,6 +3898,22 @@ gtk_ctree_insert_node (GtkCTree *ctree, gtk_ctree_link (ctree, node, parent, sibling, TRUE); + if (text && !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist) && + gtk_ctree_is_viewable (ctree, node)) + { + GtkRequisition requisition; + + for (i = 0; i < clist->columns; i++) + if (clist->column[i].auto_resize) + { + GTK_CLIST_CLASS_FW (clist)->cell_size_request (clist, + &(new_row->row), + i, &requisition); + if (requisition.width > clist->column[i].width) + gtk_clist_set_column_width (clist, i, requisition.width); + } + } + if (!GTK_CLIST_FROZEN (clist)) gtk_clist_thaw (clist); @@ -3816,9 +4076,40 @@ gtk_ctree_remove_node (GtkCTree *ctree, if (node) { + gboolean visible; + + visible = gtk_ctree_is_viewable (ctree, node); gtk_ctree_unlink (ctree, node, TRUE); gtk_ctree_post_recursive (ctree, node, GTK_CTREE_FUNC (tree_delete), NULL); + + if (!GTK_CLIST_AUTO_RESIZE_BLOCKED (clist)) + { + GtkRequisition requisition; + GList *list; + gint new_width; + gint i; + + for (i = 0; i < clist->columns; i++) + if (clist->column[i].auto_resize) + { + /* run a "gtk_clist_optimal_column_width" but break, if + * the column doesn't shrink */ + new_width = 0; + for (list = clist->row_list; list; list = list->next) + { + GTK_CLIST_CLASS_FW (clist)->cell_size_request + (clist, GTK_CLIST_ROW (list), i, &requisition); + new_width = MAX (new_width, requisition.width); + if (new_width == clist->column[i].width) + break; + } + + if (new_width < clist->column[i].width) + gtk_clist_set_column_width (clist, i, new_width); + } + } + } else gtk_clist_clear (clist); @@ -3846,11 +4137,12 @@ real_clear (GtkCList *clist) ctree->drag_target = NULL; ctree->drag_icon = NULL; - /* remove all the rows */ + /* remove all rows */ work = GTK_CTREE_NODE (clist->row_list); clist->row_list = NULL; clist->row_list_end = NULL; + GTK_CLIST_SET_FLAG (clist, CLIST_AUTO_RESIZE_BLOCKED); while (work) { ptr = work; @@ -3858,6 +4150,7 @@ real_clear (GtkCList *clist) gtk_ctree_post_recursive (ctree, ptr, GTK_CTREE_FUNC (tree_delete_row), NULL); } + GTK_CLIST_UNSET_FLAG (clist, CLIST_AUTO_RESIZE_BLOCKED); (parent_class->clear) (clist); } @@ -4353,6 +4646,7 @@ gtk_ctree_collapse_recursive (GtkCTree *ctree, { GtkCList *clist; gboolean thaw = FALSE; + gint i; g_return_if_fail (ctree != NULL); g_return_if_fail (GTK_IS_CTREE (ctree)); @@ -4369,7 +4663,13 @@ gtk_ctree_collapse_recursive (GtkCTree *ctree, thaw = TRUE; } + GTK_CLIST_SET_FLAG (clist, CLIST_AUTO_RESIZE_BLOCKED); gtk_ctree_post_recursive (ctree, node, GTK_CTREE_FUNC (tree_collapse), NULL); + GTK_CLIST_UNSET_FLAG (clist, CLIST_AUTO_RESIZE_BLOCKED); + for (i = 0; i < clist->columns; i++) + if (clist->column[i].auto_resize) + gtk_clist_set_column_width (clist, i, + gtk_clist_optimal_column_width (clist, i)); if (thaw) gtk_clist_thaw (clist); @@ -4382,6 +4682,7 @@ gtk_ctree_collapse_to_depth (GtkCTree *ctree, { GtkCList *clist; gboolean thaw = FALSE; + gint i; g_return_if_fail (ctree != NULL); g_return_if_fail (GTK_IS_CTREE (ctree)); @@ -4398,9 +4699,15 @@ gtk_ctree_collapse_to_depth (GtkCTree *ctree, thaw = TRUE; } + GTK_CLIST_SET_FLAG (clist, CLIST_AUTO_RESIZE_BLOCKED); gtk_ctree_post_recursive_to_depth (ctree, node, depth, GTK_CTREE_FUNC (tree_collapse_to_depth), GINT_TO_POINTER (depth)); + GTK_CLIST_UNSET_FLAG (clist, CLIST_AUTO_RESIZE_BLOCKED); + for (i = 0; i < clist->columns; i++) + if (clist->column[i].auto_resize) + gtk_clist_set_column_width (clist, i, + gtk_clist_optimal_column_width (clist, i)); if (thaw) gtk_clist_thaw (clist); @@ -4691,6 +4998,10 @@ gtk_ctree_node_set_shift (GtkCTree *ctree, gint vertical, gint horizontal) { + GtkCList *clist; + GtkRequisition requisition; + gboolean visible = FALSE; + g_return_if_fail (ctree != NULL); g_return_if_fail (GTK_IS_CTREE (ctree)); g_return_if_fail (node != NULL); @@ -4698,9 +5009,24 @@ gtk_ctree_node_set_shift (GtkCTree *ctree, if (column < 0 || column >= GTK_CLIST (ctree)->columns) return; + clist = GTK_CLIST (ctree); + + if (clist->column[column].auto_resize && + !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist)) + { + visible = gtk_ctree_is_viewable (ctree, node); + if (visible) + GTK_CLIST_CLASS_FW (clist)->cell_size_request + (clist, >K_CTREE_ROW (node)->row, column, &requisition); + } + GTK_CTREE_ROW (node)->row.cell[column].vertical = vertical; GTK_CTREE_ROW (node)->row.cell[column].horizontal = horizontal; + if (visible) + column_auto_resize (clist, >K_CTREE_ROW (node)->row, + column, requisition.width); + tree_draw_node (ctree, node); } @@ -4898,6 +5224,8 @@ gtk_ctree_node_set_cell_style (GtkCTree *ctree, GtkStyle *style) { GtkCList *clist; + GtkRequisition requisition; + gboolean visible = FALSE; g_return_if_fail (ctree != NULL); g_return_if_fail (GTK_IS_CTREE (ctree)); @@ -4911,6 +5239,15 @@ gtk_ctree_node_set_cell_style (GtkCTree *ctree, if (GTK_CTREE_ROW (node)->row.cell[column].style == style) return; + if (clist->column[column].auto_resize && + !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist)) + { + visible = gtk_ctree_is_viewable (ctree, node); + if (visible) + GTK_CLIST_CLASS_FW (clist)->cell_size_request + (clist, >K_CTREE_ROW (node)->row, column, &requisition); + } + if (GTK_CTREE_ROW (node)->row.cell[column].style) { if (GTK_WIDGET_REALIZED (ctree)) @@ -4930,6 +5267,10 @@ gtk_ctree_node_set_cell_style (GtkCTree *ctree, clist->clist_window); } + if (visible) + column_auto_resize (clist, >K_CTREE_ROW (node)->row, column, + requisition.width); + tree_draw_node (ctree, node); } @@ -4954,6 +5295,10 @@ gtk_ctree_node_set_row_style (GtkCTree *ctree, GtkStyle *style) { GtkCList *clist; + GtkRequisition requisition; + gboolean visible; + gint *old_width = NULL; + gint i; g_return_if_fail (ctree != NULL); g_return_if_fail (GTK_IS_CTREE (ctree)); @@ -4963,6 +5308,19 @@ gtk_ctree_node_set_row_style (GtkCTree *ctree, if (GTK_CTREE_ROW (node)->row.style == style) return; + + visible = gtk_ctree_is_viewable (ctree, node); + if (visible && !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist)) + { + old_width = g_new (gint, clist->columns); + for (i = 0; i < clist->columns; i++) + if (clist->column[i].auto_resize) + { + GTK_CLIST_CLASS_FW (clist)->cell_size_request + (clist, >K_CTREE_ROW (node)->row, i, &requisition); + old_width[i] = requisition.width; + } + } if (GTK_CTREE_ROW (node)->row.style) { @@ -4983,6 +5341,14 @@ gtk_ctree_node_set_row_style (GtkCTree *ctree, clist->clist_window); } + if (visible && !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist)) + { + for (i = 0; i < clist->columns; i++) + if (clist->column[i].auto_resize) + column_auto_resize (clist, >K_CTREE_ROW (node)->row, i, + old_width[i]); + g_free (old_width); + } tree_draw_node (ctree, node); } @@ -5115,37 +5481,57 @@ GtkVisibility gtk_ctree_node_is_visible (GtkCTree *ctree, * GtkCTree specific functions * ***********************************************************/ - void gtk_ctree_set_indent (GtkCTree *ctree, gint indent) { + GtkCList *clist; + g_return_if_fail (ctree != NULL); g_return_if_fail (GTK_IS_CTREE (ctree)); g_return_if_fail (indent >= 0); - if (indent != ctree->tree_indent) - { - ctree->tree_indent = indent; - if (!GTK_CLIST_FROZEN (ctree)) - gtk_clist_thaw (GTK_CLIST (ctree)); - } + if (indent == ctree->tree_indent) + return; + + clist = GTK_CLIST (ctree); + ctree->tree_indent = indent; + + if (clist->column[ctree->tree_column].auto_resize && + !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist)) + gtk_clist_set_column_width + (clist, ctree->tree_column, + gtk_clist_optimal_column_width (clist, ctree->tree_column)); + else if (!GTK_CLIST_FROZEN (ctree)) + gtk_clist_thaw (GTK_CLIST (ctree)); } void gtk_ctree_set_spacing (GtkCTree *ctree, gint spacing) { + GtkCList *clist; + gint old_spacing; + g_return_if_fail (ctree != NULL); g_return_if_fail (GTK_IS_CTREE (ctree)); g_return_if_fail (spacing >= 0); - if (spacing != ctree->tree_spacing) - { - ctree->tree_spacing = spacing; - if (!GTK_CLIST_FROZEN (ctree)) - gtk_clist_thaw (GTK_CLIST (ctree)); - } + if (spacing == ctree->tree_spacing) + return; + + clist = GTK_CLIST (ctree); + + old_spacing = ctree->tree_spacing; + ctree->tree_spacing = spacing; + + if (clist->column[ctree->tree_column].auto_resize && + !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist)) + gtk_clist_set_column_width (clist, ctree->tree_column, + clist->column[ctree->tree_column].width + + spacing - old_spacing); + else if (!GTK_CLIST_FROZEN (ctree)) + gtk_clist_thaw (GTK_CLIST (ctree)); } void @@ -5198,16 +5584,35 @@ void gtk_ctree_set_line_style (GtkCTree *ctree, GtkCTreeLineStyle line_style) { + GtkCList *clist; + GtkCTreeLineStyle old_style; + g_return_if_fail (ctree != NULL); g_return_if_fail (GTK_IS_CTREE (ctree)); - if (line_style != ctree->line_style) - { - ctree->line_style = line_style; + if (line_style == ctree->line_style) + return; - if (!GTK_WIDGET_REALIZED (ctree)) - return; + clist = GTK_CLIST (ctree); + + old_style = ctree->line_style; + ctree->line_style = line_style; + + if (clist->column[ctree->tree_column].auto_resize && + !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist)) + { + if (old_style == GTK_CTREE_LINES_TABBED) + gtk_clist_set_column_width + (clist, ctree->tree_column, + clist->column[ctree->tree_column].width - 3); + else if (line_style == GTK_CTREE_LINES_TABBED) + gtk_clist_set_column_width + (clist, ctree->tree_column, + clist->column[ctree->tree_column].width + 3); + } + if (GTK_WIDGET_REALIZED (ctree)) + { switch (line_style) { case GTK_CTREE_LINES_SOLID: @@ -5240,16 +5645,57 @@ void gtk_ctree_set_expander_style (GtkCTree *ctree, GtkCTreeExpanderStyle expander_style) { + GtkCList *clist; + GtkCTreeExpanderStyle old_style; + g_return_if_fail (ctree != NULL); g_return_if_fail (GTK_IS_CTREE (ctree)); - if (expander_style != ctree->expander_style) + if (expander_style == ctree->expander_style) + return; + + clist = GTK_CLIST (ctree); + + old_style = ctree->expander_style; + ctree->expander_style = expander_style; + + if (clist->column[ctree->tree_column].auto_resize && + !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist)) { - ctree->expander_style = expander_style; + gint new_width; - if (!GTK_CLIST_FROZEN (ctree)) - gtk_clist_thaw (GTK_CLIST (ctree)); + new_width = clist->column[ctree->tree_column].width; + switch (old_style) + { + case GTK_CTREE_EXPANDER_NONE: + break; + case GTK_CTREE_EXPANDER_TRIANGLE: + new_width -= PM_SIZE + 3; + break; + case GTK_CTREE_EXPANDER_SQUARE: + case GTK_CTREE_EXPANDER_CIRCULAR: + new_width -= PM_SIZE + 1; + break; + } + + switch (expander_style) + { + case GTK_CTREE_EXPANDER_NONE: + break; + case GTK_CTREE_EXPANDER_TRIANGLE: + new_width += PM_SIZE + 3; + break; + case GTK_CTREE_EXPANDER_SQUARE: + case GTK_CTREE_EXPANDER_CIRCULAR: + new_width += PM_SIZE + 1; + break; + } + + gtk_clist_set_column_width (clist, ctree->tree_column, new_width); } + + if (!GTK_CLIST_FROZEN (ctree) && GTK_WIDGET_DRAWABLE (clist)) + gtk_clist_thaw (GTK_CLIST (ctree)); } diff --git a/gtk/testgtk.c b/gtk/testgtk.c index 68ff79724d..98cb6f20ad 100644 --- a/gtk/testgtk.c +++ b/gtk/testgtk.c @@ -3542,7 +3542,7 @@ add1000_clist (GtkWidget *widget, gpointer data) gtk_clist_freeze (GTK_CLIST (data)); for (i = 0; i < 1000; i++) { - sprintf (text[0], "Row %d", rand() % 10000); + sprintf (text[0], "CListRow %d", rand() % 10000); row = gtk_clist_append (clist, texts); gtk_clist_set_pixtext (clist, row, 3, "gtk+", 5, pixmap, mask); } @@ -3572,7 +3572,7 @@ add10000_clist (GtkWidget *widget, gpointer data) gtk_clist_freeze (GTK_CLIST (data)); for (i = 0; i < 10000; i++) { - sprintf (text[0], "Row %d", rand() % 10000 /*clist_rows++*/); + sprintf (text[0], "CListRow %d", rand() % 10000); gtk_clist_append (GTK_CLIST (data), texts); } gtk_clist_thaw (GTK_CLIST (data)); @@ -3830,7 +3830,7 @@ clist_toggle_sel_mode (GtkWidget *widget, GtkCList *clist) static void clist_click_column (GtkCList *clist, gint column, gpointer data) { - if (column == 5) + if (column == 4) gtk_clist_set_column_visibility (clist, column, FALSE); else if (column == clist->sort_column) { @@ -3853,8 +3853,8 @@ create_clist (void) static char *titles[] = { - "Title 0", "Title 1", "not resizeable", "max width 120", - "min width 40", "hide column", "Title 6", "Title 7", + "auto resize", "not resizeable", "max width 100", "min width 50", + "hide column", "Title 5", "Title 6", "Title 7", "Title 8", "Title 9", "Title 10", "Title 11", "Title 12", "Title 13", "Title 14", "Title 15", "Title 16", "Title 17", "Title 18", "Title 19" @@ -4008,9 +4008,10 @@ create_clist (void) for (i = 1; i < TESTGTK_CLIST_COLUMNS; i++) gtk_clist_set_column_width (GTK_CLIST (clist), i, 80); - gtk_clist_set_column_resizeable (GTK_CLIST (clist), 2, FALSE); - gtk_clist_set_column_max_width (GTK_CLIST (clist), 3, 120); - gtk_clist_set_column_min_width (GTK_CLIST (clist), 4, 40); + gtk_clist_set_column_auto_resize (GTK_CLIST (clist), 0, TRUE); + gtk_clist_set_column_resizeable (GTK_CLIST (clist), 1, FALSE); + gtk_clist_set_column_max_width (GTK_CLIST (clist), 2, 100); + gtk_clist_set_column_min_width (GTK_CLIST (clist), 3, 50); gtk_clist_set_selection_mode (GTK_CLIST (clist), GTK_SELECTION_EXTENDED); gtk_clist_set_policy (GTK_CLIST (clist), GTK_POLICY_AUTOMATIC, @@ -4047,7 +4048,7 @@ create_clist (void) for (i = 0; i < 10; i++) { - sprintf (text[0], "Row %d", clist_rows++); + sprintf (text[0], "CListRow %d", clist_rows++); gtk_clist_append (GTK_CLIST (clist), texts); switch (i % 4) @@ -4832,8 +4833,11 @@ void create_ctree (void) button = gtk_button_new_with_label ("Rebuild tree"); gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0); - + ctree = GTK_CTREE (gtk_ctree_new_with_titles (2, 0, title)); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (rebuild_tree), ctree); + gtk_ctree_set_line_style (ctree, GTK_CTREE_LINES_DOTTED); line_style = GTK_CTREE_LINES_DOTTED; @@ -4866,12 +4870,10 @@ void create_ctree (void) gtk_clist_set_selection_mode (GTK_CLIST (ctree), GTK_SELECTION_EXTENDED); gtk_clist_set_policy (GTK_CLIST (ctree), GTK_POLICY_ALWAYS, GTK_POLICY_AUTOMATIC); - gtk_clist_set_column_width (GTK_CLIST (ctree), 0, 200); + gtk_clist_set_column_min_width (GTK_CLIST (ctree), 0, 50); + gtk_clist_set_column_auto_resize (GTK_CLIST (ctree), 0, TRUE); gtk_clist_set_column_width (GTK_CLIST (ctree), 1, 200); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (rebuild_tree), ctree); - bbox = gtk_hbox_new (FALSE, 5); gtk_container_border_width (GTK_CONTAINER (bbox), 5); gtk_box_pack_start (GTK_BOX (vbox), bbox, FALSE, TRUE, 0); @@ -6264,7 +6266,7 @@ create_dnd (void) else gtk_widget_destroy (window); } -#endif +#endif /* * Shaped Windows diff --git a/tests/testgtk.c b/tests/testgtk.c index 68ff79724d..98cb6f20ad 100644 --- a/tests/testgtk.c +++ b/tests/testgtk.c @@ -3542,7 +3542,7 @@ add1000_clist (GtkWidget *widget, gpointer data) gtk_clist_freeze (GTK_CLIST (data)); for (i = 0; i < 1000; i++) { - sprintf (text[0], "Row %d", rand() % 10000); + sprintf (text[0], "CListRow %d", rand() % 10000); row = gtk_clist_append (clist, texts); gtk_clist_set_pixtext (clist, row, 3, "gtk+", 5, pixmap, mask); } @@ -3572,7 +3572,7 @@ add10000_clist (GtkWidget *widget, gpointer data) gtk_clist_freeze (GTK_CLIST (data)); for (i = 0; i < 10000; i++) { - sprintf (text[0], "Row %d", rand() % 10000 /*clist_rows++*/); + sprintf (text[0], "CListRow %d", rand() % 10000); gtk_clist_append (GTK_CLIST (data), texts); } gtk_clist_thaw (GTK_CLIST (data)); @@ -3830,7 +3830,7 @@ clist_toggle_sel_mode (GtkWidget *widget, GtkCList *clist) static void clist_click_column (GtkCList *clist, gint column, gpointer data) { - if (column == 5) + if (column == 4) gtk_clist_set_column_visibility (clist, column, FALSE); else if (column == clist->sort_column) { @@ -3853,8 +3853,8 @@ create_clist (void) static char *titles[] = { - "Title 0", "Title 1", "not resizeable", "max width 120", - "min width 40", "hide column", "Title 6", "Title 7", + "auto resize", "not resizeable", "max width 100", "min width 50", + "hide column", "Title 5", "Title 6", "Title 7", "Title 8", "Title 9", "Title 10", "Title 11", "Title 12", "Title 13", "Title 14", "Title 15", "Title 16", "Title 17", "Title 18", "Title 19" @@ -4008,9 +4008,10 @@ create_clist (void) for (i = 1; i < TESTGTK_CLIST_COLUMNS; i++) gtk_clist_set_column_width (GTK_CLIST (clist), i, 80); - gtk_clist_set_column_resizeable (GTK_CLIST (clist), 2, FALSE); - gtk_clist_set_column_max_width (GTK_CLIST (clist), 3, 120); - gtk_clist_set_column_min_width (GTK_CLIST (clist), 4, 40); + gtk_clist_set_column_auto_resize (GTK_CLIST (clist), 0, TRUE); + gtk_clist_set_column_resizeable (GTK_CLIST (clist), 1, FALSE); + gtk_clist_set_column_max_width (GTK_CLIST (clist), 2, 100); + gtk_clist_set_column_min_width (GTK_CLIST (clist), 3, 50); gtk_clist_set_selection_mode (GTK_CLIST (clist), GTK_SELECTION_EXTENDED); gtk_clist_set_policy (GTK_CLIST (clist), GTK_POLICY_AUTOMATIC, @@ -4047,7 +4048,7 @@ create_clist (void) for (i = 0; i < 10; i++) { - sprintf (text[0], "Row %d", clist_rows++); + sprintf (text[0], "CListRow %d", clist_rows++); gtk_clist_append (GTK_CLIST (clist), texts); switch (i % 4) @@ -4832,8 +4833,11 @@ void create_ctree (void) button = gtk_button_new_with_label ("Rebuild tree"); gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0); - + ctree = GTK_CTREE (gtk_ctree_new_with_titles (2, 0, title)); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (rebuild_tree), ctree); + gtk_ctree_set_line_style (ctree, GTK_CTREE_LINES_DOTTED); line_style = GTK_CTREE_LINES_DOTTED; @@ -4866,12 +4870,10 @@ void create_ctree (void) gtk_clist_set_selection_mode (GTK_CLIST (ctree), GTK_SELECTION_EXTENDED); gtk_clist_set_policy (GTK_CLIST (ctree), GTK_POLICY_ALWAYS, GTK_POLICY_AUTOMATIC); - gtk_clist_set_column_width (GTK_CLIST (ctree), 0, 200); + gtk_clist_set_column_min_width (GTK_CLIST (ctree), 0, 50); + gtk_clist_set_column_auto_resize (GTK_CLIST (ctree), 0, TRUE); gtk_clist_set_column_width (GTK_CLIST (ctree), 1, 200); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (rebuild_tree), ctree); - bbox = gtk_hbox_new (FALSE, 5); gtk_container_border_width (GTK_CONTAINER (bbox), 5); gtk_box_pack_start (GTK_BOX (vbox), bbox, FALSE, TRUE, 0); @@ -6264,7 +6266,7 @@ create_dnd (void) else gtk_widget_destroy (window); } -#endif +#endif /* * Shaped Windows -- 2.30.2